From eugene.loh at oracle.com Mon Jan 6 15:55:25 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Mon, 6 Jan 2025 10:55:25 -0500 Subject: [DTrace-devel] [PATCH] Move proc lock to where we actually find a USDT process Message-ID: <20250106155525.15499-1-eugene.loh@oracle.com> From: Eugene Loh The function dt_pid_create_usdt_probes_proc() creates USDT probes for a specific process. It is called in one of two ways: dt_proc_scan(dtp, dpr) -> dt_pid_create_probes_module(dtp, dpr) The process has been locked and we are updating its USDT probes. dt_pid_create_usdt_probes(pdp, dtp, pcb) Here, we look for any pids that might have USDT probes, calling the pid-specific function for each candidate. One problem is that the first code path assumes the process is locked. This means the second code path has to lock processes even before we know if it has any USDT probes we care about. Change dt_pid_create_usdt_probes_proc() so the caller can specify the process in either one of two ways: by pid (implying the process has not been locked) by dpr (implying the process has been locked) In the first case, the function will lock the process, but only if USDT probes have been found. Signed-off-by: Eugene Loh --- libdtrace/dt_pid.c | 70 +++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index 8110ccead..6db882059 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -782,33 +782,42 @@ validate_dof_record(const char *path, const dof_parsed_t *parsed, /* - * Create underlying probes relating to the probespec passed on input. + * Create underlying probes relating to the probe description passed on input. + * Just set up probes relating to mappings found in this one process. * - * dpr must be set and locked. Just set up probes relating to mappings found - * in this one process. + * Either the pid must be specified or else dpr must be set and locked. * * Return 0 on success or -1 on error. (Failure to create specific underlying * probes is not an error.) */ static int -dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, dt_proc_t *dpr, +dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr, dtrace_probedesc_t *pdp, dt_pcb_t *pcb) { const dt_provider_t *pvp; int ret = 0; + int dpr_caller; /* dpr was set by caller */ char *probepath = NULL; glob_t probeglob = {0}; - assert(dpr != NULL && dpr->dpr_proc); - assert(MUTEX_HELD(&dpr->dpr_lock)); + if (dpr == NULL) { + assert(pid != -1); + dpr_caller = 0; + } else { + assert(pid == -1); + assert(dpr->dpr_proc); + assert(MUTEX_HELD(&dpr->dpr_lock)); + pid = dpr->dpr_pid; + dpr_caller = 1; + } dt_dprintf("Scanning for usdt probes in %i matching %s:%s:%s\n", - dpr->dpr_pid, pdp->mod, pdp->fun, pdp->prb); + pid, pdp->mod, pdp->fun, pdp->prb); pvp = dt_provider_lookup(dtp, "usdt"); assert(pvp != NULL); - if (Pstate(dpr->dpr_proc) == PS_DEAD) + if (dpr != NULL && Pstate(dpr->dpr_proc) == PS_DEAD) return 0; /* @@ -835,7 +844,7 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, dt_proc_t *dpr, assert(pvp->impl != NULL && pvp->impl->provide_probe != NULL); if (asprintf(&probepath, "%s/probes/%i/%s/%s/%s/%s", dtp->dt_dofstash_path, - dpr->dpr_pid, pdp->prv[0] == '\0' ? "*" : pdp->prv, + pid, pdp->prv[0] == '\0' ? "*" : pdp->prv, pdp->mod[0] == '\0' ? "*" : pdp->mod, pdp->fun[0] == '\0' ? "*" : pdp->fun, pdp->prb[0] == '\0' ? "*" : pdp->prb) < 0) @@ -858,6 +867,19 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, dt_proc_t *dpr, return 0; } + /* Set dpr and grab the process, if necessary. */ + if (dpr_caller == 0) { + if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING | + DTRACE_PROC_SHORTLIVED) < 0) { + dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, + "failed to grab process %d", (int)pid); + return -1; + } + dpr = dt_proc_lookup(dtp, pid); + assert(dpr != NULL); + } + + /* Loop over USDT probes. */ for (size_t i = 0; i < probeglob.gl_pathc; i++) { char *dof_buf = NULL, *p; struct stat s; @@ -1051,10 +1073,16 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, dt_proc_t *dpr, free(path); free(dof_buf); globfree(&probeglob); + if (dpr_caller == 0) + dt_proc_release_unlock(dtp, pid); return -1; } globfree(&probeglob); + if (dpr_caller == 0) { + dt_pid_fix_mod(NULL, pdp, dtp, pid); + dt_proc_release_unlock(dtp, pid); + } return ret; scan_err: @@ -1237,7 +1265,6 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t * + strlen(dtp->dt_dofstash_path) + strlen("/probes/"); pid_t pid; - dt_proc_t *dpr; dtrace_probedesc_t pdptmp; /* Pull out the pid. */ @@ -1247,28 +1274,15 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t * if (!Pexists(pid)) continue; - /* Grab the process. */ - if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING | - DTRACE_PROC_SHORTLIVED) < 0) { - dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, - "failed to grab process %d", (int)pid); - err = 1; // FIXME but do we want to set the error if we end up return 0? - continue; - } - dpr = dt_proc_lookup(dtp, pid); - assert(dpr != NULL); - - /* Create USDT probes for this process. */ + /* Construct the probe descriptor. */ 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; - if (dt_pid_create_usdt_probes_proc(dtp, dpr, &pdptmp, pcb)) - err = 1; - - dt_pid_fix_mod(NULL, &pdptmp, dtp, dpr->dpr_pid); - dt_proc_release_unlock(dtp, pid); + /* Create USDT probes for this process. */ + if (dt_pid_create_usdt_probes_proc(dtp, pid, NULL, &pdptmp, pcb)) + err = 1; } free(globpat); globfree(&globbuf); @@ -1341,7 +1355,7 @@ dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr) * a USDT provider. */ if (strcmp(provname, pdp->prv) != 0) { - if (dt_pid_create_usdt_probes_proc(dtp, dpr, pdp, NULL) < 0) + if (dt_pid_create_usdt_probes_proc(dtp, -1, dpr, pdp, NULL) < 0) ret = 1; else dt_pid_fix_mod(NULL, pdp, dtp, dpr->dpr_pid); -- 2.43.5 From kris.van.hees at oracle.com Mon Jan 6 19:13:43 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Mon, 6 Jan 2025 14:13:43 -0500 Subject: [DTrace-devel] [PATCH] Improve dt_pid_create_usdt_probes() error handling In-Reply-To: <20241202042741.12328-1-eugene.loh@oracle.com> References: <20241202042741.12328-1-eugene.loh@oracle.com> Message-ID: Reviewed-by: Kris Van Hees ... although I think that the problem is (in part) on the design side of USDT handling, where we do a bit too much work at this point of probe discovery, when we do not even know whether we will be using those probes. But that is subject matter for a more extensive reworking of the code. This patch seems sufficient to deal with the existing problem of DTrace being affected by unruly processes. On Sun, Dec 01, 2024 at 11:27:41PM -0500, eugene.loh at oracle.com wrote: > From: Eugene Loh > > In one run of the test suite, roughly 90 consecutive tests failed. > The exact circumstances are difficult to reconstruct, but basically > they complained with messages like: > > dtrace: failed to compile script ...: failed to grab process 23132 > > The same pid was always indicated. Then, the errors stopped. > > Apparently, the problem was trying "dtrace -s foo.d" where the script > has a BEGIN (or END) probe. Then we get to > > cmd/dtrace.c compile_file > -> libdtrace/dt_cc.c dt_program_compile > -> libdtrace/dt_cc.c dt_compile > -> libdtrace/dt_cc.c dt_compile_one_clause > -> libdtrace/dt_cc.c dt_setcontext > -> libdtrace/dt_pid.c dt_pid_create_usdt_probes > > We look for processes that might have USDT probes. Since the provider > description is blank, we check every process in .../run/dtrace. It > turned out, that pid 23132 could not be locked. This sent an error > back up the call stack. > > We do not know why process 23132 could not be locked, but having dtrace > fail under these circumstances (using BEGIN or END probe) seems severe. > > Change dt_pid_create_usdt_probes() error handling. Even if there is a > problem with some USDT processes, report success anyhow if there was a > glob pid specification. If, on the other hand, a pid was specifically > requested, then a problem with that pid results in an error. > > Signed-off-by: Eugene Loh > --- > libdtrace/dt_pid.c | 35 +++++++++++++++++++++++++++++++++-- > 1 file changed, 33 insertions(+), 2 deletions(-) > > diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c > index e0a26d5aa..fd94a0706 100644 > --- a/libdtrace/dt_pid.c > +++ b/libdtrace/dt_pid.c > @@ -1252,7 +1252,8 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t * > DTRACE_PROC_SHORTLIVED) < 0) { > dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, > "failed to grab process %d", (int)pid); > - return -1; > + err = 1; // FIXME but do we want to set the error if we end up return 0? > + continue; > } > dpr = dt_proc_lookup(dtp, pid); > assert(dpr != NULL); > @@ -1272,7 +1273,37 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t * > free(globpat); > globfree(&globbuf); > > - return err ? -1 : 0; > + /* If no errors, report success. */ > + if (err == 0) > + return 0; > + > + /* If provider description was blank, report success. */ > + if (pdp->prv[0] == '\0') > + return 0; > + > + /* Look to see if the provider description had a pid glob. */ > + for (i = strlen(pdp->prv) - 1; i >= 0; i--) { > + /* > + * If we hit a '*' before a nondigit, we have a pid glob. > + * So, even though err==0, we declare success. > + */ > + if (pdp->prv[i] == '*') > + return 0; > + > + /* > + * If we hit a nondigit before a '*', we do not have a pid glob. > + * Since a pid was specified explicitly, err==1 means an error. > + */ > + if (!isdigit(pdp->prv[i])) > + return -1; > + } > + > + /* > + * If the provider description was exclusively digits, > + * it was not a legitimate USDT provider description. > + * So it makes perfect sense not to return any probes. > + */ > + return 0; > } > > int > -- > 2.43.5 > From kris.van.hees at oracle.com Mon Jan 6 20:50:33 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Mon, 6 Jan 2025 15:50:33 -0500 Subject: [DTrace-devel] [PATCH] test: Retry umount if necessary In-Reply-To: <20241203201601.28787-1-eugene.loh@oracle.com> References: <20241203201601.28787-1-eugene.loh@oracle.com> Message-ID: On Tue, Dec 03, 2024 at 03:16:01PM -0500, eugene.loh at oracle.com wrote: > From: Eugene Loh > > The io tests tst.local.sh and tst.wait.sh fail with some frequency, > with error messages like "umount: $iodir: target is busy." > > Modify the tests' dtrace trigger, doio.sh, so that it will retry > umount a few times, if necessary. Specifically, remove the "set -e" > and individually check for and report errors, in the case of umount > retrying a few times before giving up. > > While we're at it, notice that the two tests use the same $iodir. > There is no need for the tests to be coupled in this way. Change > those two tests so that each test has a fresh value of iodir. > > Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees ... I did read the discussion about lazy umount, but I think that in terms of what is best for the testsuite, being able to ascertain that the umount is actually getting done (or reporting an error on it) is important in case later tests might get affected by it. Lazy umount seems like it would lead to possible silent umount conditions which is not ideal for a test. > --- > test/triggers/doio.sh | 29 ++++++++++++++++++++++++++--- > test/unittest/io/tst.local.sh | 2 +- > test/unittest/io/tst.wait.sh | 2 +- > 3 files changed, 28 insertions(+), 5 deletions(-) > > diff --git a/test/triggers/doio.sh b/test/triggers/doio.sh > index a2a39c245..0171a4b4c 100755 > --- a/test/triggers/doio.sh > +++ b/test/triggers/doio.sh > @@ -22,15 +22,38 @@ mountdir=$4 > mountarg1=${5-""} > mountarg2=${6-""} > > -set -e > - > # do writes > dd if=/dev/urandom of=$tempfile count=$filesize bs=1 status=none > +if [ $? -ne 0 ]; then > + echo ERROR dd > + exit 1 > +fi > > # flush cache and remount the file system to force the IO > -umount $mountdir > +ntries=3 > +while [ $ntries -gt 0 ]; do > + umount $mountdir >& /dev/null > + if [ $? -eq 0 ]; then > + break > + fi > + sleep 1 > + ntries=$(($ntries - 1)) > +done > +if [ $ntries -eq 0 ]; then > + echo ERROR umount > + exit 1 > +fi > + > echo 3 > /proc/sys/vm/drop_caches > $mountcmd $mountdir $mountarg1 $mountarg2 > +if [ $? -ne 0 ]; then > + echo ERROR $mountcmd > + exit 1 > +fi > > # do reads > sum $tempfile > /dev/null > +if [ $? -ne 0 ]; then > + echo ERROR sum > + exit 1 > +fi > diff --git a/test/unittest/io/tst.local.sh b/test/unittest/io/tst.local.sh > index d3dbf1713..702c6f453 100755 > --- a/test/unittest/io/tst.local.sh > +++ b/test/unittest/io/tst.local.sh > @@ -18,7 +18,7 @@ minsize=$((filesize / 10 * 9)) > fstype=xfs > # file system-specific options > fsoptions="defaults,atime,diratime,nosuid,nodev" > -iodir=$tmpdir/test-$fstype-io > +iodir=$tmpdir/test-$fstype-io-local.$$ > tempfile=`mktemp -u -p $iodir` > > trap "umount $iodir; rmdir $iodir; rm -f $iodir.img" QUIT EXIT > diff --git a/test/unittest/io/tst.wait.sh b/test/unittest/io/tst.wait.sh > index 016b922eb..24ac2e436 100755 > --- a/test/unittest/io/tst.wait.sh > +++ b/test/unittest/io/tst.wait.sh > @@ -15,7 +15,7 @@ filesize=$((1024*$nblocks)) > fstype=xfs > # file system-specific options > fsoptions="defaults,atime,diratime,nosuid,nodev" > -iodir=$tmpdir/test-$fstype-io > +iodir=$tmpdir/test-$fstype-io-wait.$$ > tempfile=`mktemp -u -p $iodir` > > trap "umount $iodir; rmdir $iodir; rm -f $iodir.img" QUIT EXIT > -- > 2.43.5 > From kris.van.hees at oracle.com Mon Jan 6 21:04:25 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Mon, 6 Jan 2025 16:04:25 -0500 Subject: [DTrace-devel] [PATCH] test: Allow duplicate usym/umod/uaddr if for different pids In-Reply-To: <20241205191318.18587-1-eugene.loh@oracle.com> References: <20241205191318.18587-1-eugene.loh@oracle.com> Message-ID: On Thu, Dec 05, 2024 at 02:13:18PM -0500, eugene.loh at oracle.com wrote: > From: Eugene Loh > > In 83da884cbdc5 ("Preface usym/umod/uaddr with pid"), a bug was fixed > in which addresses in the same module (or function) might be mapped to > multiple agg entries. This fix helped the associated tests run much > more successfully. Nonetheless, tests would sometimes still fail. > > Another problem is that the tests themselves were overly narrow. It > is fine for a module (or function) to appear multiple times in the > aggregation output... if those entries correspond to different pids. > > Further, odd behaviors can result for some of the processes running on > a system. > > Change the tests to add a "pid" agg key. Filter on only a few, select > pids. Distinguish agg entries by pid. > > There are still occasional time outs observed with these tests, > presumably because the tick-2s probe is not firing (when profile-1234hz > is running). > > Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees > --- > test/unittest/profile-n/tst.ufunc.sh | 12 ++++++++---- > test/unittest/profile-n/tst.umod.sh | 11 ++++++++--- > test/unittest/profile-n/tst.usym.sh | 11 ++++++++--- > 3 files changed, 24 insertions(+), 10 deletions(-) > > diff --git a/test/unittest/profile-n/tst.ufunc.sh b/test/unittest/profile-n/tst.ufunc.sh > index 243822407..f5174a1e2 100755 > --- a/test/unittest/profile-n/tst.ufunc.sh > +++ b/test/unittest/profile-n/tst.ufunc.sh > @@ -11,10 +11,14 @@ tmpfile=$tmpdir/tst.profile_ufunc.$$ > script() > { > $dtrace $dt_flags -qs /dev/stdin < + BEGIN > + { > + printf("dtrace is %d\n", \$pid); > + } > profile-1234hz > /arg1 != 0/ > { > - @[ufunc(arg1)] = count(); > + @[ufunc(arg1), pid] = count(); > } > > tick-2s > @@ -52,9 +56,9 @@ if ! grep -q 'bash`[a-zA-Z_]' $tmpfile; then > status=1 > fi > > -# Check that functions are unique. (Exclude shared libraries and unresolved addresses.) > -if gawk '!/^ *(ld-linux-|lib|([^`]*`)?0x)/ {print $1}' $tmpfile | \ > - sort | uniq -c | grep -qv " 1 "; then > +# Check that functions are unique for each pid that interests us. > +dtpid=`awk '/^dtrace is [0-9]*$/ { print $3 }' $tmpfile` > +if gawk '$2 == '$child' || $2 == '$dtpid' {print $1, $2}' $tmpfile | sort | uniq -c | grep -qv " 1 "; then > echo ERROR: duplicate ufunc > status=1 > fi > diff --git a/test/unittest/profile-n/tst.umod.sh b/test/unittest/profile-n/tst.umod.sh > index 45d2b1e9b..7cfe2a073 100755 > --- a/test/unittest/profile-n/tst.umod.sh > +++ b/test/unittest/profile-n/tst.umod.sh > @@ -11,10 +11,14 @@ tmpfile=$tmpdir/tst.profile_umod.$$ > script() > { > $dtrace $dt_flags -qs /dev/stdin < + BEGIN > + { > + printf("dtrace is %d\n", \$pid); > + } > profile-1234hz > /arg1 != 0/ > { > - @[umod(arg1)] = count(); > + @[umod(arg1), pid] = count(); > } > > tick-2s > @@ -52,8 +56,9 @@ if ! grep -wq 'bash' $tmpfile; then > status=1 > fi > > -# Check that modules are unique. (Exclude shared libraries and unresolved addresses.) > -if gawk '!/^ *lib/ && !/^ *ld-.*\.so / && !/^ *0x/ {print $1}' $tmpfile | sort | uniq -c | grep -qv " 1 "; then > +# Check that modules are unique for each pid that interests us. > +dtpid=`awk '/^dtrace is [0-9]*$/ { print $3 }' $tmpfile` > +if gawk '$2 == '$child' || $2 == '$dtpid' {print $1, $2}' $tmpfile | sort | uniq -c | grep -qv " 1 "; then > echo ERROR: duplicate umod > status=1 > fi > diff --git a/test/unittest/profile-n/tst.usym.sh b/test/unittest/profile-n/tst.usym.sh > index 634e633b3..8e373b976 100755 > --- a/test/unittest/profile-n/tst.usym.sh > +++ b/test/unittest/profile-n/tst.usym.sh > @@ -11,10 +11,14 @@ tmpfile=$tmpdir/tst.profile_usym.$$ > script() > { > $dtrace $dt_flags -qs /dev/stdin < + BEGIN > + { > + printf("dtrace is %d\n", \$pid); > + } > profile-1234hz > /arg1 != 0/ > { > - @[usym(arg1)] = count(); > + @[usym(arg1), pid] = count(); > } > > tick-2s > @@ -52,8 +56,9 @@ if ! grep -q 'bash`[a-zA-Z_]' $tmpfile; then > status=1 > fi > > -# Check that symbols are unique. (Exclude shared libraries and unresolved addresses.) > -if gawk '!/^ *lib/ && !/^ *0x/ {print $1}' $tmpfile | sort | uniq -c | grep -qv " 1 "; then > +# Check that symbols are unique for each pid that interests us. > +dtpid=`awk '/^dtrace is [0-9]*$/ { print $3 }' $tmpfile` > +if gawk '$2 == '$child' || $2 == '$dtpid' {print $1, $2}' $tmpfile | sort | uniq -c | grep -qv " 1 "; then > echo ERROR: duplicate usym > status=1 > fi > -- > 2.43.5 > From kris.van.hees at oracle.com Mon Jan 6 21:14:04 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Mon, 6 Jan 2025 16:14:04 -0500 Subject: [DTrace-devel] [PATCH] test: Have USDT "deferred" tests wait for dtrace to start In-Reply-To: <20241210230202.16603-1-eugene.loh@oracle.com> References: <20241210230202.16603-1-eugene.loh@oracle.com> Message-ID: On Tue, Dec 10, 2024 at 06:02:02PM -0500, eugene.loh at oracle.com wrote: > From: Eugene Loh > > Systemwide USDT tracing includes having dtrace track USDT processes > that start after it does. Associated tests start dtrace first, wait > a few seconds, and then start processes to be traced. > > Waiting "a few seconds" can be insufficient, especially on slower > systems or as more work is being performed during dtrace startup. > > Change tests to wait for dtrace to start by polling on the output file. > > Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees ... though hopefully in the very near future we will not need this anymore, so we should revisit this once we have better (more timely) detection of USDT probes. Otherwise these tests might result in hiding issues with the timely detection of the probes. But for now, this is needed to ensure we have proper functional testing. > --- > test/unittest/usdt/err.Z_no-w.sh | 17 ++++++++++++++--- > test/unittest/usdt/tst.defer-Z.sh | 17 ++++++++++++++--- > test/unittest/usdt/tst.defer.sh | 17 ++++++++++++++--- > test/unittest/usdt/tst.nusdtprobes.sh | 16 +++++++++++++--- > 4 files changed, 55 insertions(+), 12 deletions(-) > > diff --git a/test/unittest/usdt/err.Z_no-w.sh b/test/unittest/usdt/err.Z_no-w.sh > index 3833b4400..4f129341d 100755 > --- a/test/unittest/usdt/err.Z_no-w.sh > +++ b/test/unittest/usdt/err.Z_no-w.sh > @@ -34,9 +34,20 @@ testprov*:::foo > raise(SIGUSR1); > }' & > dtpid=$! > -sleep 4 > -if [[ ! -d /proc/$dtpid ]]; then > - echo ERROR dtrace died prematurely > + > +# Wait up to half of the timeout period for dtrace to start up. > + > +iter=$((timeout / 2)) > +while [ $iter -gt 0 ]; do > + sleep 1 > + if [ -e dtrace.out ]; then > + break > + fi > + iter=$((iter - 1)) > +done > +if [[ $iter -eq 0 ]]; then > + echo ERROR starting DTrace job > + cat dtrace.out > exit 1 > fi > > diff --git a/test/unittest/usdt/tst.defer-Z.sh b/test/unittest/usdt/tst.defer-Z.sh > index 52e92eb6b..ff2c5cbf1 100755 > --- a/test/unittest/usdt/tst.defer-Z.sh > +++ b/test/unittest/usdt/tst.defer-Z.sh > @@ -45,9 +45,20 @@ testprov*4:::bar > @[pid, 3] = sum(pid % 100); > }' & > dtpid=$! > -sleep 2 > -if [[ ! -d /proc/$dtpid ]]; then > - echo ERROR dtrace died > + > +# Wait up to half of the timeout period for dtrace to start up. > + > +iter=$((timeout / 2)) > +while [ $iter -gt 0 ]; do > + sleep 1 > + if [ -e dtrace.out ]; then > + break > + fi > + iter=$((iter - 1)) > +done > +if [[ $iter -eq 0 ]]; then > + echo ERROR starting DTrace job > + cat dtrace.out > exit 1 > fi > > diff --git a/test/unittest/usdt/tst.defer.sh b/test/unittest/usdt/tst.defer.sh > index 02ed1a767..073af12d5 100755 > --- a/test/unittest/usdt/tst.defer.sh > +++ b/test/unittest/usdt/tst.defer.sh > @@ -51,9 +51,20 @@ testprov*'$lastdigit':::bar > @[pid, 3] = sum(pid % 100); > }' & > dtpid=$! > -sleep 2 > -if [[ ! -d /proc/$dtpid ]]; then > - echo ERROR dtrace died > + > +# Wait up to half of the timeout period for dtrace to start up. > + > +iter=$((timeout / 2)) > +while [ $iter -gt 0 ]; do > + sleep 1 > + if [ -e dtrace.out ]; then > + break > + fi > + iter=$((iter - 1)) > +done > +if [[ $iter -eq 0 ]]; then > + echo ERROR starting DTrace job > + cat dtrace.out > kill -USR1 ${pids[0]} > wait ${pids[0]} > exit 1 > diff --git a/test/unittest/usdt/tst.nusdtprobes.sh b/test/unittest/usdt/tst.nusdtprobes.sh > index d2d80fe8d..f275f921f 100755 > --- a/test/unittest/usdt/tst.nusdtprobes.sh > +++ b/test/unittest/usdt/tst.nusdtprobes.sh > @@ -105,9 +105,19 @@ for nusdt in "" "-xnusdtprobes=40" "-xnusdtprobes=39"; do > @[probeprov, probemod, probefunc, probename] = count(); > }' & > dtpid=$! > - sleep 2 > - if [[ ! -d /proc/$dtpid ]]; then > - echo ERROR dtrace died > + > + # Wait a little for dtrace to start up. > + > + iter=$((timeout / 4)) > + while [ $iter -gt 0 ]; do > + sleep 1 > + if [ -e dtrace.out ]; then > + break > + fi > + iter=$((iter - 1)) > + done > + if [[ $iter -eq 0 ]]; then > + echo ERROR starting DTrace job > cat dtrace.out > exit 1 > fi > -- > 2.43.5 > From eugene.loh at oracle.com Mon Jan 6 21:36:09 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Mon, 6 Jan 2025 16:36:09 -0500 Subject: [DTrace-devel] [PATCH] test: Have USDT "deferred" tests wait for dtrace to start In-Reply-To: References: <20241210230202.16603-1-eugene.loh@oracle.com> Message-ID: <4f101016-33db-2dc7-5f2b-9ed262298b70@oracle.com> On 1/6/25 16:14, Kris Van Hees wrote: > On Tue, Dec 10, 2024 at 06:02:02PM -0500, eugene.loh at oracle.com wrote: >> From: Eugene Loh >> >> Systemwide USDT tracing includes having dtrace track USDT processes >> that start after it does. Associated tests start dtrace first, wait >> a few seconds, and then start processes to be traced. >> >> Waiting "a few seconds" can be insufficient, especially on slower >> systems or as more work is being performed during dtrace startup. >> >> Change tests to wait for dtrace to start by polling on the output file. >> >> Signed-off-by: Eugene Loh > Reviewed-by: Kris Van Hees > > ... though hopefully in the very near future we will not need this anymore, > so we should revisit this once we have better (more timely) detection of USDT > probes. Otherwise these tests might result in hiding issues with the timely > detection of the probes. Yes, but such stricter tests already exist.? It's just that they xfail for now, given our current level of support. > But for now, this is needed to ensure we have proper functional testing. > >> --- >> test/unittest/usdt/err.Z_no-w.sh | 17 ++++++++++++++--- >> test/unittest/usdt/tst.defer-Z.sh | 17 ++++++++++++++--- >> test/unittest/usdt/tst.defer.sh | 17 ++++++++++++++--- >> test/unittest/usdt/tst.nusdtprobes.sh | 16 +++++++++++++--- >> 4 files changed, 55 insertions(+), 12 deletions(-) >> >> diff --git a/test/unittest/usdt/err.Z_no-w.sh b/test/unittest/usdt/err.Z_no-w.sh >> index 3833b4400..4f129341d 100755 >> --- a/test/unittest/usdt/err.Z_no-w.sh >> +++ b/test/unittest/usdt/err.Z_no-w.sh >> @@ -34,9 +34,20 @@ testprov*:::foo >> raise(SIGUSR1); >> }' & >> dtpid=$! >> -sleep 4 >> -if [[ ! -d /proc/$dtpid ]]; then >> - echo ERROR dtrace died prematurely >> + >> +# Wait up to half of the timeout period for dtrace to start up. >> + >> +iter=$((timeout / 2)) >> +while [ $iter -gt 0 ]; do >> + sleep 1 >> + if [ -e dtrace.out ]; then >> + break >> + fi >> + iter=$((iter - 1)) >> +done >> +if [[ $iter -eq 0 ]]; then >> + echo ERROR starting DTrace job >> + cat dtrace.out >> exit 1 >> fi >> >> diff --git a/test/unittest/usdt/tst.defer-Z.sh b/test/unittest/usdt/tst.defer-Z.sh >> index 52e92eb6b..ff2c5cbf1 100755 >> --- a/test/unittest/usdt/tst.defer-Z.sh >> +++ b/test/unittest/usdt/tst.defer-Z.sh >> @@ -45,9 +45,20 @@ testprov*4:::bar >> @[pid, 3] = sum(pid % 100); >> }' & >> dtpid=$! >> -sleep 2 >> -if [[ ! -d /proc/$dtpid ]]; then >> - echo ERROR dtrace died >> + >> +# Wait up to half of the timeout period for dtrace to start up. >> + >> +iter=$((timeout / 2)) >> +while [ $iter -gt 0 ]; do >> + sleep 1 >> + if [ -e dtrace.out ]; then >> + break >> + fi >> + iter=$((iter - 1)) >> +done >> +if [[ $iter -eq 0 ]]; then >> + echo ERROR starting DTrace job >> + cat dtrace.out >> exit 1 >> fi >> >> diff --git a/test/unittest/usdt/tst.defer.sh b/test/unittest/usdt/tst.defer.sh >> index 02ed1a767..073af12d5 100755 >> --- a/test/unittest/usdt/tst.defer.sh >> +++ b/test/unittest/usdt/tst.defer.sh >> @@ -51,9 +51,20 @@ testprov*'$lastdigit':::bar >> @[pid, 3] = sum(pid % 100); >> }' & >> dtpid=$! >> -sleep 2 >> -if [[ ! -d /proc/$dtpid ]]; then >> - echo ERROR dtrace died >> + >> +# Wait up to half of the timeout period for dtrace to start up. >> + >> +iter=$((timeout / 2)) >> +while [ $iter -gt 0 ]; do >> + sleep 1 >> + if [ -e dtrace.out ]; then >> + break >> + fi >> + iter=$((iter - 1)) >> +done >> +if [[ $iter -eq 0 ]]; then >> + echo ERROR starting DTrace job >> + cat dtrace.out >> kill -USR1 ${pids[0]} >> wait ${pids[0]} >> exit 1 >> diff --git a/test/unittest/usdt/tst.nusdtprobes.sh b/test/unittest/usdt/tst.nusdtprobes.sh >> index d2d80fe8d..f275f921f 100755 >> --- a/test/unittest/usdt/tst.nusdtprobes.sh >> +++ b/test/unittest/usdt/tst.nusdtprobes.sh >> @@ -105,9 +105,19 @@ for nusdt in "" "-xnusdtprobes=40" "-xnusdtprobes=39"; do >> @[probeprov, probemod, probefunc, probename] = count(); >> }' & >> dtpid=$! >> - sleep 2 >> - if [[ ! -d /proc/$dtpid ]]; then >> - echo ERROR dtrace died >> + >> + # Wait a little for dtrace to start up. >> + >> + iter=$((timeout / 4)) >> + while [ $iter -gt 0 ]; do >> + sleep 1 >> + if [ -e dtrace.out ]; then >> + break >> + fi >> + iter=$((iter - 1)) >> + done >> + if [[ $iter -eq 0 ]]; then >> + echo ERROR starting DTrace job >> cat dtrace.out >> exit 1 >> fi >> -- >> 2.43.5 >> From kris.van.hees at oracle.com Mon Jan 6 23:44:37 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Mon, 6 Jan 2025 18:44:37 -0500 Subject: [DTrace-devel] [PATCH] test: Allow duplicate usym/umod/uaddr if for different pids In-Reply-To: References: <20241205191318.18587-1-eugene.loh@oracle.com> Message-ID: Withdrawing R-b for now after seeing these tests fail after this patch was merged. Needs further investigation. On Mon, Jan 06, 2025 at 04:04:25PM -0500, Kris Van Hees wrote: > On Thu, Dec 05, 2024 at 02:13:18PM -0500, eugene.loh at oracle.com wrote: > > From: Eugene Loh > > > > In 83da884cbdc5 ("Preface usym/umod/uaddr with pid"), a bug was fixed > > in which addresses in the same module (or function) might be mapped to > > multiple agg entries. This fix helped the associated tests run much > > more successfully. Nonetheless, tests would sometimes still fail. > > > > Another problem is that the tests themselves were overly narrow. It > > is fine for a module (or function) to appear multiple times in the > > aggregation output... if those entries correspond to different pids. > > > > Further, odd behaviors can result for some of the processes running on > > a system. > > > > Change the tests to add a "pid" agg key. Filter on only a few, select > > pids. Distinguish agg entries by pid. > > > > There are still occasional time outs observed with these tests, > > presumably because the tick-2s probe is not firing (when profile-1234hz > > is running). > > > > Signed-off-by: Eugene Loh > > Reviewed-by: Kris Van Hees > > > --- > > test/unittest/profile-n/tst.ufunc.sh | 12 ++++++++---- > > test/unittest/profile-n/tst.umod.sh | 11 ++++++++--- > > test/unittest/profile-n/tst.usym.sh | 11 ++++++++--- > > 3 files changed, 24 insertions(+), 10 deletions(-) > > > > diff --git a/test/unittest/profile-n/tst.ufunc.sh b/test/unittest/profile-n/tst.ufunc.sh > > index 243822407..f5174a1e2 100755 > > --- a/test/unittest/profile-n/tst.ufunc.sh > > +++ b/test/unittest/profile-n/tst.ufunc.sh > > @@ -11,10 +11,14 @@ tmpfile=$tmpdir/tst.profile_ufunc.$$ > > script() > > { > > $dtrace $dt_flags -qs /dev/stdin < > + BEGIN > > + { > > + printf("dtrace is %d\n", \$pid); > > + } > > profile-1234hz > > /arg1 != 0/ > > { > > - @[ufunc(arg1)] = count(); > > + @[ufunc(arg1), pid] = count(); > > } > > > > tick-2s > > @@ -52,9 +56,9 @@ if ! grep -q 'bash`[a-zA-Z_]' $tmpfile; then > > status=1 > > fi > > > > -# Check that functions are unique. (Exclude shared libraries and unresolved addresses.) > > -if gawk '!/^ *(ld-linux-|lib|([^`]*`)?0x)/ {print $1}' $tmpfile | \ > > - sort | uniq -c | grep -qv " 1 "; then > > +# Check that functions are unique for each pid that interests us. > > +dtpid=`awk '/^dtrace is [0-9]*$/ { print $3 }' $tmpfile` > > +if gawk '$2 == '$child' || $2 == '$dtpid' {print $1, $2}' $tmpfile | sort | uniq -c | grep -qv " 1 "; then > > echo ERROR: duplicate ufunc > > status=1 > > fi > > diff --git a/test/unittest/profile-n/tst.umod.sh b/test/unittest/profile-n/tst.umod.sh > > index 45d2b1e9b..7cfe2a073 100755 > > --- a/test/unittest/profile-n/tst.umod.sh > > +++ b/test/unittest/profile-n/tst.umod.sh > > @@ -11,10 +11,14 @@ tmpfile=$tmpdir/tst.profile_umod.$$ > > script() > > { > > $dtrace $dt_flags -qs /dev/stdin < > + BEGIN > > + { > > + printf("dtrace is %d\n", \$pid); > > + } > > profile-1234hz > > /arg1 != 0/ > > { > > - @[umod(arg1)] = count(); > > + @[umod(arg1), pid] = count(); > > } > > > > tick-2s > > @@ -52,8 +56,9 @@ if ! grep -wq 'bash' $tmpfile; then > > status=1 > > fi > > > > -# Check that modules are unique. (Exclude shared libraries and unresolved addresses.) > > -if gawk '!/^ *lib/ && !/^ *ld-.*\.so / && !/^ *0x/ {print $1}' $tmpfile | sort | uniq -c | grep -qv " 1 "; then > > +# Check that modules are unique for each pid that interests us. > > +dtpid=`awk '/^dtrace is [0-9]*$/ { print $3 }' $tmpfile` > > +if gawk '$2 == '$child' || $2 == '$dtpid' {print $1, $2}' $tmpfile | sort | uniq -c | grep -qv " 1 "; then > > echo ERROR: duplicate umod > > status=1 > > fi > > diff --git a/test/unittest/profile-n/tst.usym.sh b/test/unittest/profile-n/tst.usym.sh > > index 634e633b3..8e373b976 100755 > > --- a/test/unittest/profile-n/tst.usym.sh > > +++ b/test/unittest/profile-n/tst.usym.sh > > @@ -11,10 +11,14 @@ tmpfile=$tmpdir/tst.profile_usym.$$ > > script() > > { > > $dtrace $dt_flags -qs /dev/stdin < > + BEGIN > > + { > > + printf("dtrace is %d\n", \$pid); > > + } > > profile-1234hz > > /arg1 != 0/ > > { > > - @[usym(arg1)] = count(); > > + @[usym(arg1), pid] = count(); > > } > > > > tick-2s > > @@ -52,8 +56,9 @@ if ! grep -q 'bash`[a-zA-Z_]' $tmpfile; then > > status=1 > > fi > > > > -# Check that symbols are unique. (Exclude shared libraries and unresolved addresses.) > > -if gawk '!/^ *lib/ && !/^ *0x/ {print $1}' $tmpfile | sort | uniq -c | grep -qv " 1 "; then > > +# Check that symbols are unique for each pid that interests us. > > +dtpid=`awk '/^dtrace is [0-9]*$/ { print $3 }' $tmpfile` > > +if gawk '$2 == '$child' || $2 == '$dtpid' {print $1, $2}' $tmpfile | sort | uniq -c | grep -qv " 1 "; then > > echo ERROR: duplicate usym > > status=1 > > fi > > -- > > 2.43.5 > > From noreply at github.com Tue Jan 7 04:03:55 2025 From: noreply at github.com (Kris Van Hees) Date: Mon, 06 Jan 2025 20:03:55 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] Message-ID: Branch: refs/tags/2.0.2 Home: https://github.com/oracle/dtrace-utils To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From noreply at github.com Tue Jan 7 04:05:55 2025 From: noreply at github.com (Kris Van Hees) Date: Mon, 06 Jan 2025 20:05:55 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] Message-ID: Branch: refs/tags/2.0.2-rc1 Home: https://github.com/oracle/dtrace-utils To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From noreply at github.com Tue Jan 7 04:08:17 2025 From: noreply at github.com (euloh) Date: Mon, 06 Jan 2025 20:08:17 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] 174398: Improve dt_pid_create_usdt_probes() error handling Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: 1743984a98285e989251e97b23fa7c38f8e00eb2 https://github.com/oracle/dtrace-utils/commit/1743984a98285e989251e97b23fa7c38f8e00eb2 Author: Eugene Loh Date: 2025-01-06 (Mon, 06 Jan 2025) Changed paths: M libdtrace/dt_pid.c Log Message: ----------- Improve dt_pid_create_usdt_probes() error handling In one run of the test suite, roughly 90 consecutive tests failed. The exact circumstances are difficult to reconstruct, but basically they complained with messages like: dtrace: failed to compile script ...: failed to grab process 23132 The same pid was always indicated. Then, the errors stopped. Apparently, the problem was trying "dtrace -s foo.d" where the script has a BEGIN (or END) probe. Then we get to cmd/dtrace.c compile_file -> libdtrace/dt_cc.c dt_program_compile -> libdtrace/dt_cc.c dt_compile -> libdtrace/dt_cc.c dt_compile_one_clause -> libdtrace/dt_cc.c dt_setcontext -> libdtrace/dt_pid.c dt_pid_create_usdt_probes We look for processes that might have USDT probes. Since the provider description is blank, we check every process in .../run/dtrace. It turned out, that pid 23132 could not be locked. This sent an error back up the call stack. We do not know why process 23132 could not be locked, but having dtrace fail under these circumstances (using BEGIN or END probe) seems severe. Change dt_pid_create_usdt_probes() error handling. Even if there is a problem with some USDT processes, report success anyhow if there was a glob pid specification. If, on the other hand, a pid was specifically requested, then a problem with that pid results in an error. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Commit: 297c990bfc13e7033010f052dc6a9c37b76abc10 https://github.com/oracle/dtrace-utils/commit/297c990bfc13e7033010f052dc6a9c37b76abc10 Author: Eugene Loh Date: 2025-01-06 (Mon, 06 Jan 2025) Changed paths: M test/triggers/doio.sh M test/unittest/io/tst.local.sh M test/unittest/io/tst.wait.sh Log Message: ----------- test: Retry umount if necessary The io tests tst.local.sh and tst.wait.sh fail with some frequency, with error messages like "umount: $iodir: target is busy." Modify the tests' dtrace trigger, doio.sh, so that it will retry umount a few times, if necessary. Specifically, remove the "set -e" and individually check for and report errors, in the case of umount retrying a few times before giving up. While we're at it, notice that the two tests use the same $iodir. There is no need for the tests to be coupled in this way. Change those two tests so that each test has a fresh value of iodir. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Commit: 220c0bc201ab097ca3b972551a5e728e218391ca https://github.com/oracle/dtrace-utils/commit/220c0bc201ab097ca3b972551a5e728e218391ca Author: Eugene Loh Date: 2025-01-06 (Mon, 06 Jan 2025) Changed paths: M test/unittest/usdt/err.Z_no-w.sh M test/unittest/usdt/tst.defer-Z.sh M test/unittest/usdt/tst.defer.sh M test/unittest/usdt/tst.nusdtprobes.sh Log Message: ----------- test: Have USDT "deferred" tests wait for dtrace to start Systemwide USDT tracing includes having dtrace track USDT processes that start after it does. Associated tests start dtrace first, wait a few seconds, and then start processes to be traced. Waiting "a few seconds" can be insufficient, especially on slower systems or as more work is being performed during dtrace startup. Change tests to wait for dtrace to start by polling on the output file. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Commit: 7383d6dd3e2a31973b4f04d30e0cbd43174366d9 https://github.com/oracle/dtrace-utils/commit/7383d6dd3e2a31973b4f04d30e0cbd43174366d9 Author: Eugene Loh Date: 2025-01-06 (Mon, 06 Jan 2025) Changed paths: M test/unittest/dtrace-util/tst.ListProbesArgsUSDT.sh M test/unittest/dtrace-util/tst.ListProbesFunc.sh M test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh M test/unittest/dtrace-util/tst.ListProbesName.sh M test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh M test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh Log Message: ----------- test: Make tests more resilient to changes in start-up performance The tests with no target might start dtrace many times. The test time-out values should be long enough to withstand many starts even on slow test systems. Use time-out values for dtrace start-up times of as long as 10 seconds. The tests with a target might start the target first and then expect more than one dtrace to start up and find that target. Make sure the target runs sufficiently long. Do not worry about making the target run too long, since the test will kill the target anyhow once it is no longer needed. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Commit: 228f11db8c2f7a4b37ea58f64a815452fcf6f597 https://github.com/oracle/dtrace-utils/commit/228f11db8c2f7a4b37ea58f64a815452fcf6f597 Author: Eugene Loh Date: 2025-01-06 (Mon, 06 Jan 2025) Changed paths: M test/unittest/usdt/tst.multiple.sh Log Message: ----------- test: Improve sync mechanism in tst.multiple.sh In this test, a USDT process is launched. Subsequently, dtrace is started. To give dtrace a chance to enable the USDT probes, the USDT process waits a few seconds. On some systems and when the amount of work dtrace does upon startup is high, "a few seconds" may not be enough, causing the test to miss expected probes. Have the USDT process loop on an is-enabled probe; this is a more resilient sync mechanism between it and dtrace. That said, dtrace does not enable all probes in one instant, and it makes no promises in what order probes will be started. So, we still leave a (shorter) sleep() in the target process. Arguably, the test could be simplified by launching the USDT process with "dtrace -c". In this patch, we choose instead to retain the overall character of the existing test. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Commit: 352417d422d9e2f0fbe2eecf1440de2bb2b3d0d0 https://github.com/oracle/dtrace-utils/commit/352417d422d9e2f0fbe2eecf1440de2bb2b3d0d0 Author: Eugene Loh Date: 2025-01-06 (Mon, 06 Jan 2025) Changed paths: M test/triggers/usdt-tst-defer.c Log Message: ----------- test: Lengthen the delay in USDT defer trigger. The trigger usdt-tst-defer.c expects that, as soon as probe foo is enabled, so too are the foo and bar is-enabled probes as well as the bar probe. Since they are not turned on absolutely concurrently, the trigger actually has a microsleep after foo is enabled and before further activity is resumed. Nonetheless, there is evidence in occasional test runs that some events are missed. Since there are no guarantees how concurrently these probes are turned on, lengthen the delay. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Commit: 1eb9b20470d8b6607db0ff553a4b787c95c24b13 https://github.com/oracle/dtrace-utils/commit/1eb9b20470d8b6607db0ff553a4b787c95c24b13 Author: Eugene Loh Date: 2025-01-06 (Mon, 06 Jan 2025) Changed paths: M libdtrace/dt_pid.c Log Message: ----------- Use prb instead of psp.pps_prb Replace psp.pps_prb with prb, both because it is simpler and more importantly psp.pps_prb has not yet been assigned! Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Commit: f450921c04b175bbb7201246b0c4bfce6a318fb6 https://github.com/oracle/dtrace-utils/commit/f450921c04b175bbb7201246b0c4bfce6a318fb6 Author: Eugene Loh Date: 2025-01-06 (Mon, 06 Jan 2025) Changed paths: M test/unittest/usdt/tst.dlclose4.sh Log Message: ----------- test: Disown child pid for cleaner stderr Extend commit 9546afc22 ("test: Disown child pid for cleaner stderr") to include another test. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/d68b4e26e7d5...f450921c04b1 To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From noreply at github.com Tue Jan 7 04:08:17 2025 From: noreply at github.com (Kris Van Hees) Date: Mon, 06 Jan 2025 20:08:17 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] Message-ID: Branch: refs/tags/2.0.2-rc2 Home: https://github.com/oracle/dtrace-utils To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From kris.van.hees at oracle.com Tue Jan 7 22:44:23 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 7 Jan 2025 17:44:23 -0500 Subject: [DTrace-devel] [PATCH] io: adjust io provider for NFS tracepoint variants Message-ID: Kernels prior to 5.6.0 pass 3 arguments (derived from the NFS hdr) to the nfs_initiate_read raw tracepoint, whereas kernels as of 5.6.0 pass just the NFS hdr. Signed-off-by: Kris Van Hees --- libdtrace/dt_prov_io.c | 127 +++++++++++++++++++++++++++++++++++------ 1 file changed, 108 insertions(+), 19 deletions(-) diff --git a/libdtrace/dt_prov_io.c b/libdtrace/dt_prov_io.c index 385dc792..45cb875a 100644 --- a/libdtrace/dt_prov_io.c +++ b/libdtrace/dt_prov_io.c @@ -63,17 +63,9 @@ static probe_dep_t probes[] = { { "start", DTRACE_PROBESPEC_NAME, "rawtp:block::block_bio_queue" }, { "start", - DTRACE_PROBESPEC_NAME, "rawtp:nfs::nfs_initiate_read", - DT_VERSION_NUMBER(5, 6, 0), }, + DTRACE_PROBESPEC_NAME, "rawtp:nfs::nfs_initiate_read" }, { "start", - DTRACE_PROBESPEC_NAME, "fbt:nfs:nfs_initiate_read:entry", - 0, DT_VERSION_NUMBER(5, 5, 19) }, - { "start", - DTRACE_PROBESPEC_NAME, "rawtp:nfs::nfs_initiate_write", - DT_VERSION_NUMBER(5, 6, 0), }, - { "start", - DTRACE_PROBESPEC_NAME, "fbt:nfs:nfs_initiate_write:entry", - 0, DT_VERSION_NUMBER(5, 5, 19) }, + DTRACE_PROBESPEC_NAME, "rawtp:nfs::nfs_initiate_write" }, { NULL, } }; @@ -155,12 +147,109 @@ static void deref_r3(dt_irlist_t *dlp, uint_t exitlbl, int addend, int width, emit(dlp, BPF_LOAD(width, reg, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); } +/* + * For NFS events, we have to construct a fake struct bio, which we have to + * populate from the inode (arg0) and hdr->good_bytes (arg2) arguments the + * underlying probe provides. + */ +static void io_nfs_args_v1(dt_pcb_t *pcb, dt_irlist_t *dlp, uint_t exitlbl, + const char *prb, const char *uprb) +{ + int off; + size_t siz; + + /* + * Determine the various sizes and offsets we want. + * + * // Access these fields relative to &bio. + * struct bio bio = { + * .bi_opf = ..., + * .bi_iter.bi_size = ..., // struct bvec_iter bi_iter + * .bi_iter.bi_sector = ..., + * .bi_bdev = 0, // -or- .bi_disk = 0 + * }; + * + * // Access these fields relative to hdr. + * struct nfs_pgio_header *hdr; + * ... = hdr->res.count; // struct nfs_pgio_res res + */ + + /* + * Declare the -io-bio variable and store its address in %r6. + */ + dt_cg_tramp_decl_var(pcb, &v_bio); + dt_cg_tramp_get_var(pcb, "this->-io-bio", 1, BPF_REG_6); + + /* Fill in bi_opf */ + off = dt_cg_ctf_offsetof("struct bio", "bi_opf", &siz, 0); + siz = bpf_ldst_size(siz, 1); + if (strstr(uprb, "read")) + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, REQ_OP_READ)); + else + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, REQ_OP_WRITE)); + + /* + * bio.bi_iter.bi_size = hdr->foo.count; + * + * For the 'start' probe, count is arg2 + * For the 'done' probe, count is hdr->res.count (hdr in arg1) + */ + if (strcmp(prb, "start") == 0) { + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(2))); + } else { + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(1))); + off = dt_cg_ctf_offsetof("struct nfs_pgio_header", "res", NULL, 0) + + dt_cg_ctf_offsetof("struct nfs_pgio_res", "count", &siz, 0); + deref_r3(dlp, exitlbl, off, siz, BPF_REG_0); + } + + off = dt_cg_ctf_offsetof("struct bio", "bi_iter", NULL, 0) + + dt_cg_ctf_offsetof("struct bvec_iter", "bi_size", &siz, 0); + siz = bpf_ldst_size(siz, 1); + emit(dlp, BPF_STORE(siz, BPF_REG_6, off, BPF_REG_0)); + + /* + * bio.bi_iter.bi_sector = inode; + */ + if (strcmp(prb, "start") == 0) { + /* inode is arg0 */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(0))); + } else { + /* use hdr->inode, hdr is arg1 */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(1))); + + off = dt_cg_ctf_offsetof("struct nfs_pgio_header", "inode", &siz, 0); + deref_r3(dlp, exitlbl, off, siz, BPF_REG_3); + } + + off = dt_cg_ctf_offsetof("struct nfs_inode", "fileid", &siz, 0) + - dt_cg_ctf_offsetof("struct nfs_inode", "vfs_inode", NULL, 0); + deref_r3(dlp, exitlbl, off, siz, BPF_REG_0); + + off = dt_cg_ctf_offsetof("struct bio", "bi_iter", NULL, 0) + + dt_cg_ctf_offsetof("struct bvec_iter", "bi_sector", &siz, 0); + siz = bpf_ldst_size(siz, 1); + emit(dlp, BPF_STORE(siz, BPF_REG_6, off, BPF_REG_0)); + + /* + * bio.bi_bdev = 0; + */ + off = dt_cg_ctf_offsetof("struct bio", "bi_bdev", &siz, 1); + if (off == -1) + off = dt_cg_ctf_offsetof("struct bio", "bi_disk", &siz, 0); + siz = bpf_ldst_size(siz, 1); + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, 0)); + + /* Store a pointer to the fake bio in arg0. */ + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_6)); +} + /* * For NFS events, we have to construct a fake struct bio, which we have to * populate from the nfs_pgio_header argument the underlying probe provides. */ -static void io_nfs_args(dt_pcb_t *pcb, dt_irlist_t *dlp, uint_t exitlbl, - const char *prb, const char *uprb) +static void io_nfs_args_v2(dt_pcb_t *pcb, dt_irlist_t *dlp, uint_t exitlbl, + const char *prb, const char *uprb) { int off; size_t siz; @@ -411,6 +500,7 @@ static void io_xfs_args(dt_pcb_t *pcb, dt_irlist_t *dlp, uint_t exitlbl) */ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) { + dtrace_hdl_t *dtp = pcb->pcb_hdl; dt_irlist_t *dlp = &pcb->pcb_ir; dt_probe_t *prp = pcb->pcb_probe; dt_probe_t *uprp = pcb->pcb_parent_probe; @@ -420,13 +510,12 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) * we need to synthesize one. */ if (strcmp(uprp->desc->mod, "nfs") == 0) { - /* - * If the underlying probe is an FBT probe, we pass function - * name. Otherwise, pass probe name. - */ - io_nfs_args(pcb, dlp, exitlbl, prp->desc->prb, - strcmp(uprp->desc->prb, "entry") == 0 - ? uprp->desc->fun : uprp->desc->prb); + if (dtp->dt_kernver < DT_VERSION_NUMBER(5, 6, 0)) + io_nfs_args_v1(pcb, dlp, exitlbl, prp->desc->prb, + uprp->desc->prb); + else + io_nfs_args_v2(pcb, dlp, exitlbl, prp->desc->prb, + uprp->desc->prb); goto done; } else if (strcmp(uprp->desc->mod, "xfs") == 0) { io_xfs_args(pcb, dlp, exitlbl); -- 2.45.2 From elena.zannoni at oracle.com Wed Jan 8 01:47:53 2025 From: elena.zannoni at oracle.com (Elena Zannoni) Date: Tue, 7 Jan 2025 18:47:53 -0700 Subject: [DTrace-devel] [PATCH] io: adjust io provider for NFS tracepoint variants In-Reply-To: References: Message-ID: Reviewed-by: Elena Zannoni elena On 1/7/25 15:44, Kris Van Hees wrote: > Kernels prior to 5.6.0 pass 3 arguments (derived from the NFS hdr) > to the nfs_initiate_read raw tracepoint, whereas kernels as of 5.6.0 > pass just the NFS hdr. > > Signed-off-by: Kris Van Hees > --- > libdtrace/dt_prov_io.c | 127 +++++++++++++++++++++++++++++++++++------ > 1 file changed, 108 insertions(+), 19 deletions(-) > > diff --git a/libdtrace/dt_prov_io.c b/libdtrace/dt_prov_io.c > index 385dc792..45cb875a 100644 > --- a/libdtrace/dt_prov_io.c > +++ b/libdtrace/dt_prov_io.c > @@ -63,17 +63,9 @@ static probe_dep_t probes[] = { > { "start", > DTRACE_PROBESPEC_NAME, "rawtp:block::block_bio_queue" }, > { "start", > - DTRACE_PROBESPEC_NAME, "rawtp:nfs::nfs_initiate_read", > - DT_VERSION_NUMBER(5, 6, 0), }, > + DTRACE_PROBESPEC_NAME, "rawtp:nfs::nfs_initiate_read" }, > { "start", > - DTRACE_PROBESPEC_NAME, "fbt:nfs:nfs_initiate_read:entry", > - 0, DT_VERSION_NUMBER(5, 5, 19) }, > - { "start", > - DTRACE_PROBESPEC_NAME, "rawtp:nfs::nfs_initiate_write", > - DT_VERSION_NUMBER(5, 6, 0), }, > - { "start", > - DTRACE_PROBESPEC_NAME, "fbt:nfs:nfs_initiate_write:entry", > - 0, DT_VERSION_NUMBER(5, 5, 19) }, > + DTRACE_PROBESPEC_NAME, "rawtp:nfs::nfs_initiate_write" }, > { NULL, } > }; > > @@ -155,12 +147,109 @@ static void deref_r3(dt_irlist_t *dlp, uint_t exitlbl, int addend, int width, > emit(dlp, BPF_LOAD(width, reg, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); > } > > +/* > + * For NFS events, we have to construct a fake struct bio, which we have to > + * populate from the inode (arg0) and hdr->good_bytes (arg2) arguments the > + * underlying probe provides. > + */ > +static void io_nfs_args_v1(dt_pcb_t *pcb, dt_irlist_t *dlp, uint_t exitlbl, > + const char *prb, const char *uprb) > +{ > + int off; > + size_t siz; > + > + /* > + * Determine the various sizes and offsets we want. > + * > + * // Access these fields relative to &bio. > + * struct bio bio = { > + * .bi_opf = ..., > + * .bi_iter.bi_size = ..., // struct bvec_iter bi_iter > + * .bi_iter.bi_sector = ..., > + * .bi_bdev = 0, // -or- .bi_disk = 0 > + * }; > + * > + * // Access these fields relative to hdr. > + * struct nfs_pgio_header *hdr; > + * ... = hdr->res.count; // struct nfs_pgio_res res > + */ > + > + /* > + * Declare the -io-bio variable and store its address in %r6. > + */ > + dt_cg_tramp_decl_var(pcb, &v_bio); > + dt_cg_tramp_get_var(pcb, "this->-io-bio", 1, BPF_REG_6); > + > + /* Fill in bi_opf */ > + off = dt_cg_ctf_offsetof("struct bio", "bi_opf", &siz, 0); > + siz = bpf_ldst_size(siz, 1); > + if (strstr(uprb, "read")) > + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, REQ_OP_READ)); > + else > + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, REQ_OP_WRITE)); > + > + /* > + * bio.bi_iter.bi_size = hdr->foo.count; > + * > + * For the 'start' probe, count is arg2 > + * For the 'done' probe, count is hdr->res.count (hdr in arg1) > + */ > + if (strcmp(prb, "start") == 0) { > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(2))); > + } else { > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(1))); > + off = dt_cg_ctf_offsetof("struct nfs_pgio_header", "res", NULL, 0) > + + dt_cg_ctf_offsetof("struct nfs_pgio_res", "count", &siz, 0); > + deref_r3(dlp, exitlbl, off, siz, BPF_REG_0); > + } > + > + off = dt_cg_ctf_offsetof("struct bio", "bi_iter", NULL, 0) > + + dt_cg_ctf_offsetof("struct bvec_iter", "bi_size", &siz, 0); > + siz = bpf_ldst_size(siz, 1); > + emit(dlp, BPF_STORE(siz, BPF_REG_6, off, BPF_REG_0)); > + > + /* > + * bio.bi_iter.bi_sector = inode; > + */ > + if (strcmp(prb, "start") == 0) { > + /* inode is arg0 */ > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(0))); > + } else { > + /* use hdr->inode, hdr is arg1 */ > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(1))); > + > + off = dt_cg_ctf_offsetof("struct nfs_pgio_header", "inode", &siz, 0); > + deref_r3(dlp, exitlbl, off, siz, BPF_REG_3); > + } > + > + off = dt_cg_ctf_offsetof("struct nfs_inode", "fileid", &siz, 0) > + - dt_cg_ctf_offsetof("struct nfs_inode", "vfs_inode", NULL, 0); > + deref_r3(dlp, exitlbl, off, siz, BPF_REG_0); > + > + off = dt_cg_ctf_offsetof("struct bio", "bi_iter", NULL, 0) > + + dt_cg_ctf_offsetof("struct bvec_iter", "bi_sector", &siz, 0); > + siz = bpf_ldst_size(siz, 1); > + emit(dlp, BPF_STORE(siz, BPF_REG_6, off, BPF_REG_0)); > + > + /* > + * bio.bi_bdev = 0; > + */ > + off = dt_cg_ctf_offsetof("struct bio", "bi_bdev", &siz, 1); > + if (off == -1) > + off = dt_cg_ctf_offsetof("struct bio", "bi_disk", &siz, 0); > + siz = bpf_ldst_size(siz, 1); > + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, 0)); > + > + /* Store a pointer to the fake bio in arg0. */ > + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_6)); > +} > + > /* > * For NFS events, we have to construct a fake struct bio, which we have to > * populate from the nfs_pgio_header argument the underlying probe provides. > */ > -static void io_nfs_args(dt_pcb_t *pcb, dt_irlist_t *dlp, uint_t exitlbl, > - const char *prb, const char *uprb) > +static void io_nfs_args_v2(dt_pcb_t *pcb, dt_irlist_t *dlp, uint_t exitlbl, > + const char *prb, const char *uprb) > { > int off; > size_t siz; > @@ -411,6 +500,7 @@ static void io_xfs_args(dt_pcb_t *pcb, dt_irlist_t *dlp, uint_t exitlbl) > */ > static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) > { > + dtrace_hdl_t *dtp = pcb->pcb_hdl; > dt_irlist_t *dlp = &pcb->pcb_ir; > dt_probe_t *prp = pcb->pcb_probe; > dt_probe_t *uprp = pcb->pcb_parent_probe; > @@ -420,13 +510,12 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) > * we need to synthesize one. > */ > if (strcmp(uprp->desc->mod, "nfs") == 0) { > - /* > - * If the underlying probe is an FBT probe, we pass function > - * name. Otherwise, pass probe name. > - */ > - io_nfs_args(pcb, dlp, exitlbl, prp->desc->prb, > - strcmp(uprp->desc->prb, "entry") == 0 > - ? uprp->desc->fun : uprp->desc->prb); > + if (dtp->dt_kernver < DT_VERSION_NUMBER(5, 6, 0)) > + io_nfs_args_v1(pcb, dlp, exitlbl, prp->desc->prb, > + uprp->desc->prb); > + else > + io_nfs_args_v2(pcb, dlp, exitlbl, prp->desc->prb, > + uprp->desc->prb); > goto done; > } else if (strcmp(uprp->desc->mod, "xfs") == 0) { > io_xfs_args(pcb, dlp, exitlbl); From noreply at github.com Wed Jan 8 03:55:47 2025 From: noreply at github.com (Kris Van Hees) Date: Tue, 07 Jan 2025 19:55:47 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] a0a24e: io: adjust io provider for NFS tracepoint variants Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: a0a24ebf2a41ea4d93d9fe76656dc821fed6e960 https://github.com/oracle/dtrace-utils/commit/a0a24ebf2a41ea4d93d9fe76656dc821fed6e960 Author: Kris Van Hees Date: 2025-01-07 (Tue, 07 Jan 2025) Changed paths: M libdtrace/dt_prov_io.c Log Message: ----------- io: adjust io provider for NFS tracepoint variants Kernels prior to 5.6.0 pass 3 arguments (derived from the NFS hdr) to the nfs_initiate_read raw tracepoint, whereas kernels as of 5.6.0 pass just the NFS hdr. Signed-off-by: Kris Van Hees Reviewed-by: Elena Zannoni To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From noreply at github.com Wed Jan 8 03:55:47 2025 From: noreply at github.com (Kris Van Hees) Date: Tue, 07 Jan 2025 19:55:47 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] Message-ID: Branch: refs/tags/2.0.2-rc3 Home: https://github.com/oracle/dtrace-utils To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From eugene.loh at oracle.com Wed Jan 8 06:01:28 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Wed, 8 Jan 2025 01:01:28 -0500 Subject: [DTrace-devel] [PATCH] io: adjust io provider for NFS tracepoint variants In-Reply-To: References: Message-ID: <474ca7db-5d3c-0426-7b17-fb04043544c5@oracle.com> You already have a R-b, it seems the code is right (woo hoo! cool), and we're trying to get a release out the door.? But here are my "late to the party" comments.? Feel free to ignore. The names v1 and v2 strike me as funny;? they just make up new numbers.? Not a big deal, but ideally the names might more closely reflect the actual version changes we're tracking. Breaking the function out into a new "v1" version is some unneeded copy-and-paste code bloat, I think.? The function is kind of large and the only difference between v1 and v2 is I guess in the two, relatively short, "start" sections.? So, keeping this stuff as one function -- with extra logic in the two "start" sections -- might be more compact and clearer than having two rather similar functions. On 1/7/25 17:44, Kris Van Hees wrote: > Kernels prior to 5.6.0 pass 3 arguments (derived from the NFS hdr) > to the nfs_initiate_read raw tracepoint, whereas kernels as of 5.6.0 > pass just the NFS hdr. Is the same true of write?? If so, then maybe say so and point out that what we're really doing is changing the handling of nfs "start" while leaving nfs "done" alone...? that would correspond more closely to what is happening in the code, which talks of start and done. > Signed-off-by: Kris Van Hees > --- > libdtrace/dt_prov_io.c | 127 +++++++++++++++++++++++++++++++++++------ > 1 file changed, 108 insertions(+), 19 deletions(-) > > diff --git a/libdtrace/dt_prov_io.c b/libdtrace/dt_prov_io.c > @@ -155,12 +147,109 @@ static void deref_r3(dt_irlist_t *dlp, uint_t exitlbl, int addend, int width, > +/* > + * For NFS events, we have to construct a fake struct bio, which we have to > + * populate from the inode (arg0) and hdr->good_bytes (arg2) arguments the > + * underlying probe provides. > + */ > +static void io_nfs_args_v1(dt_pcb_t *pcb, dt_irlist_t *dlp, uint_t exitlbl, > + const char *prb, const char *uprb) > +{ > + int off; > + size_t siz; > + > + /* > + * Determine the various sizes and offsets we want. > + * > + * // Access these fields relative to &bio. > + * struct bio bio = { > + * .bi_opf = ..., > + * .bi_iter.bi_size = ..., // struct bvec_iter bi_iter > + * .bi_iter.bi_sector = ..., > + * .bi_bdev = 0, // -or- .bi_disk = 0 > + * }; > + * > + * // Access these fields relative to hdr. > + * struct nfs_pgio_header *hdr; > + * ... = hdr->res.count; // struct nfs_pgio_res res > + */ > + > + /* > + * Declare the -io-bio variable and store its address in %r6. > + */ > + dt_cg_tramp_decl_var(pcb, &v_bio); > + dt_cg_tramp_get_var(pcb, "this->-io-bio", 1, BPF_REG_6); > + > + /* Fill in bi_opf */ > + off = dt_cg_ctf_offsetof("struct bio", "bi_opf", &siz, 0); > + siz = bpf_ldst_size(siz, 1); > + if (strstr(uprb, "read")) > + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, REQ_OP_READ)); > + else > + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, REQ_OP_WRITE)); > + > + /* > + * bio.bi_iter.bi_size = hdr->foo.count; If "v1" is broken out, then this hdr->foo.count no longer makes sense.? Plus, the comment is more or less superseded by the following two comment lines. Or, mimic how the comments are handled below for inode. > + * > + * For the 'start' probe, count is arg2 > + * For the 'done' probe, count is hdr->res.count (hdr in arg1) > + */ > + if (strcmp(prb, "start") == 0) { > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(2))); > + } else { > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(1))); > + off = dt_cg_ctf_offsetof("struct nfs_pgio_header", "res", NULL, 0) > + + dt_cg_ctf_offsetof("struct nfs_pgio_res", "count", &siz, 0); > + deref_r3(dlp, exitlbl, off, siz, BPF_REG_0); > + } > + > + off = dt_cg_ctf_offsetof("struct bio", "bi_iter", NULL, 0) > + + dt_cg_ctf_offsetof("struct bvec_iter", "bi_size", &siz, 0); > + siz = bpf_ldst_size(siz, 1); > + emit(dlp, BPF_STORE(siz, BPF_REG_6, off, BPF_REG_0)); > + > + /* > + * bio.bi_iter.bi_sector = inode; > + */ > + if (strcmp(prb, "start") == 0) { > + /* inode is arg0 */ > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(0))); > + } else { > + /* use hdr->inode, hdr is arg1 */ > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(1))); > + > + off = dt_cg_ctf_offsetof("struct nfs_pgio_header", "inode", &siz, 0); > + deref_r3(dlp, exitlbl, off, siz, BPF_REG_3); > + } > + > + off = dt_cg_ctf_offsetof("struct nfs_inode", "fileid", &siz, 0) > + - dt_cg_ctf_offsetof("struct nfs_inode", "vfs_inode", NULL, 0); > + deref_r3(dlp, exitlbl, off, siz, BPF_REG_0); > + > + off = dt_cg_ctf_offsetof("struct bio", "bi_iter", NULL, 0) > + + dt_cg_ctf_offsetof("struct bvec_iter", "bi_sector", &siz, 0); > + siz = bpf_ldst_size(siz, 1); > + emit(dlp, BPF_STORE(siz, BPF_REG_6, off, BPF_REG_0)); > + > + /* > + * bio.bi_bdev = 0; > + */ > + off = dt_cg_ctf_offsetof("struct bio", "bi_bdev", &siz, 1); > + if (off == -1) > + off = dt_cg_ctf_offsetof("struct bio", "bi_disk", &siz, 0); > + siz = bpf_ldst_size(siz, 1); > + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, 0)); > + > + /* Store a pointer to the fake bio in arg0. */ > + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_6)); > +} From nick.alcock at oracle.com Wed Jan 8 11:34:36 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Wed, 08 Jan 2025 11:34:36 +0000 Subject: [DTrace-devel] [PATCH] io: adjust io provider for NFS tracepoint variants In-Reply-To: <474ca7db-5d3c-0426-7b17-fb04043544c5@oracle.com> (Eugene Loh's message of "Wed, 8 Jan 2025 01:01:28 -0500") References: <474ca7db-5d3c-0426-7b17-fb04043544c5@oracle.com> Message-ID: <87ed1dh73n.fsf@esperi.org.uk> On 8 Jan 2025, Eugene Loh uttered the following: > You already have a R-b, it seems the code is right (woo hoo! cool), and we're trying to get a release out the door.? But here are my > "late to the party" comments.? Feel free to ignore. Ditto :) > The names v1 and v2 strike me as funny;? they just make up new numbers.? Not a big deal, but ideally the names might more closely > reflect the actual version changes we're tracking. Agreed. > Breaking the function out into a new "v1" version is some unneeded copy-and-paste code bloat, I think.? The function is kind of > large and the only difference between v1 and v2 is I guess in the two, relatively short, "start" sections.? So, keeping this stuff > as one function -- with extra logic in the two "start" sections -- might be more compact and clearer than having two rather similar > functions. Agreed, but more generally it seems we are growing increasingly many fairly similar fake bio functions in the io provider: with this I think we're up to three. Maybe it's time to refactor some of this into some sort of shared fake bio machinery? Certainly if we grow more I think we should (and given the number of network filesystems, that seems quite likely to happen). > On 1/7/25 17:44, Kris Van Hees wrote: >> Kernels prior to 5.6.0 pass 3 arguments (derived from the NFS hdr) >> to the nfs_initiate_read raw tracepoint, whereas kernels as of 5.6.0 >> pass just the NFS hdr. > > Is the same true of write?? If so, then maybe say so and point out that what we're really doing is changing the handling of nfs > "start" while leaving nfs "done" alone...? that would correspond more closely to what is happening in the code, which talks of start > and done. Good thinkiing. That would be commit 5bb2a7cb9fe58d2b1efedd6058d442c7871c45ec ("NFS: Clean up generic writeback tracepoints"), also by Trond, also first landing in 5.6-rc1. Same sort of thing. From nick.alcock at oracle.com Thu Jan 9 16:47:10 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Thu, 9 Jan 2025 16:47:10 +0000 Subject: [DTrace-devel] [PATCH] tests: add test for buggy deduplicator Message-ID: <20250109164711.232013-1-nick.alcock@oracle.com> Some early prototype deduplicators dedupped types in one dict (more or less) rather than putting conflicting types and module types into sub-dictionaries. Fail if the running kernel is such a kernel. Signed-off-by: Nick Alcock --- dtrace.spec | 2 +- test/smoke/tst.ctf-intact.sh | 58 ++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100755 test/smoke/tst.ctf-intact.sh diff --git a/dtrace.spec b/dtrace.spec index 902ad7d8bb980..cf960f14b55c7 100644 --- a/dtrace.spec +++ b/dtrace.spec @@ -151,7 +151,7 @@ Requires: %{name}-devel = %{version}-%{release} perl gcc java Requires: java-1.8.0-openjdk-devel perl-IO-Socket-IP xfsprogs Requires: exportfs vim-minimal %{name}%{?_isa} = %{version}-%{release} Requires: coreutils wireshark %{glibc32} -Requires: perf time bc nfs-utils +Requires: perf time bc nfs-utils binutils Autoreq: 0 Group: Development/System diff --git a/test/smoke/tst.ctf-intact.sh b/test/smoke/tst.ctf-intact.sh new file mode 100755 index 0000000000000..d737a2b162fcb --- /dev/null +++ b/test/smoke/tst.ctf-intact.sh @@ -0,0 +1,58 @@ +#!/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 script verifies that the CTF, if present, is non-corrupt: in +# particular, that it has at least one child with +# + +ctf="/lib/modules/$(uname -r)/kernel/vmlinux.ctfa" + +if [[ ! -f "$ctf" ]]; then + echo "CTF not found in expected location of $ctf" >&2 + exit 67 +fi + +# If this is not an ELF file, turn it into one so objdump works. +if ! [[ "$(file "$ctf")" =~ ELF ]]; then + objcopy --add-section=.ctf="$ctf" /bin/true $tmpdir/ctf + ctf=$tmpdir/ctf +fi + +# Dump the CTF +objdump --ctf --ctf-parent=shared_ctf "$ctf" 2>/dev/null | \ + awk ' +BEGIN { + intypes=0; +} + +/^ Strings:|^CTF archive member:/ { + intypes = 0; +} +# Scan for each member, capture its name. +/^CTF archive member: / { + member=gensub (/CTF archive member: (.*):/,"\\1", "g"); + next; +} +# See if any non-shared dicts have any types in. +/^ Types:/ { + if (member != "shared_ctf") { + intypes=1; + } +} +/^ 0x/ { + if (intypes) { + exit (0); + } +} +END { + if (!intypes) { + printf ("No non-shared-dict types found: probably buggy deduplicator.\n"); + exit (1); + } +}' -- 2.47.1.279.g84c5f4e78e From kris.van.hees at oracle.com Thu Jan 9 17:09:09 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 9 Jan 2025 12:09:09 -0500 Subject: [DTrace-devel] [PATCH] tests: add test for buggy deduplicator In-Reply-To: <20250109164711.232013-1-nick.alcock@oracle.com> References: <20250109164711.232013-1-nick.alcock@oracle.com> Message-ID: On Thu, Jan 09, 2025 at 04:47:10PM +0000, Nick Alcock via DTrace-devel wrote: > Some early prototype deduplicators dedupped types in one dict (more or less) > rather than putting conflicting types and module types into > sub-dictionaries. Fail if the running kernel is such a kernel. > > Signed-off-by: Nick Alcock > --- > dtrace.spec | 2 +- > test/smoke/tst.ctf-intact.sh | 58 ++++++++++++++++++++++++++++++++++++ > 2 files changed, 59 insertions(+), 1 deletion(-) > create mode 100755 test/smoke/tst.ctf-intact.sh > > diff --git a/dtrace.spec b/dtrace.spec > index 902ad7d8bb980..cf960f14b55c7 100644 > --- a/dtrace.spec > +++ b/dtrace.spec > @@ -151,7 +151,7 @@ Requires: %{name}-devel = %{version}-%{release} perl gcc java > Requires: java-1.8.0-openjdk-devel perl-IO-Socket-IP xfsprogs > Requires: exportfs vim-minimal %{name}%{?_isa} = %{version}-%{release} > Requires: coreutils wireshark %{glibc32} > -Requires: perf time bc nfs-utils > +Requires: perf time bc nfs-utils binutils > Autoreq: 0 > Group: Development/System > > diff --git a/test/smoke/tst.ctf-intact.sh b/test/smoke/tst.ctf-intact.sh > new file mode 100755 > index 0000000000000..d737a2b162fcb > --- /dev/null > +++ b/test/smoke/tst.ctf-intact.sh > @@ -0,0 +1,58 @@ > +#!/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 script verifies that the CTF, if present, is non-corrupt: in > +# particular, that it has at least one child with ... rest of the sentence is missing? > +# > + > +ctf="/lib/modules/$(uname -r)/kernel/vmlinux.ctfa" > + > +if [[ ! -f "$ctf" ]]; then > + echo "CTF not found in expected location of $ctf" >&2 > + exit 67 > +fi > + > +# If this is not an ELF file, turn it into one so objdump works. > +if ! [[ "$(file "$ctf")" =~ ELF ]]; then > + objcopy --add-section=.ctf="$ctf" /bin/true $tmpdir/ctf > + ctf=$tmpdir/ctf > +fi > + > +# Dump the CTF > +objdump --ctf --ctf-parent=shared_ctf "$ctf" 2>/dev/null | \ > + awk ' > +BEGIN { > + intypes=0; > +} > + > +/^ Strings:|^CTF archive member:/ { > + intypes = 0; > +} > +# Scan for each member, capture its name. > +/^CTF archive member: / { > + member=gensub (/CTF archive member: (.*):/,"\\1", "g"); > + next; > +} > +# See if any non-shared dicts have any types in. > +/^ Types:/ { > + if (member != "shared_ctf") { > + intypes=1; > + } > +} > +/^ 0x/ { > + if (intypes) { > + exit (0); > + } > +} > +END { > + if (!intypes) { > + printf ("No non-shared-dict types found: probably buggy deduplicator.\n"); > + exit (1); > + } > +}' > -- > 2.47.1.279.g84c5f4e78e > > > _______________________________________________ > DTrace-devel mailing list > DTrace-devel at oss.oracle.com > https://oss.oracle.com/mailman/listinfo/dtrace-devel From kris.van.hees at oracle.com Thu Jan 9 18:15:27 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 9 Jan 2025 13:15:27 -0500 Subject: [DTrace-devel] [PATCH] io: adjust io provider for NFS tracepoint variants In-Reply-To: <474ca7db-5d3c-0426-7b17-fb04043544c5@oracle.com> References: <474ca7db-5d3c-0426-7b17-fb04043544c5@oracle.com> Message-ID: On Wed, Jan 08, 2025 at 01:01:28AM -0500, Eugene Loh wrote: > You already have a R-b, it seems the code is right (woo hoo! cool), and > we're trying to get a release out the door.? But here are my "late to the > party" comments.? Feel free to ignore. > > The names v1 and v2 strike me as funny;? they just make up new numbers.? Not > a big deal, but ideally the names might more closely reflect the actual > version changes we're tracking. The point of using v1 and v2 is really to reflect that there are two variants of the tracepoints. I deliberately did not associate them (through their name) with specific kernel versions because that fails very quickly when people start doing things like backports. With the current naming, the implementation is reflecting the 1st variant of the tracepoints vs the 2nd variant. The logic to use one vs the other is handled where that choice needs to be made. This naming also allows for a future choice to perhaps differentiate based on e.g. prototype of the tracepoint rather than a kernel version (again, that would handle backported patches much more graceafully). > Breaking the function out into a new "v1" version is some unneeded > copy-and-paste code bloat, I think.? The function is kind of large and the > only difference between v1 and v2 is I guess in the two, relatively short, > "start" sections.? So, keeping this stuff as one function -- with extra > logic in the two "start" sections -- might be more compact and clearer than > having two rather similar functions. The main point of the bloat is to make it very clear what we are doing here and why. There certainly is opportunity for refactoring the code, but this was not the time for it. > On 1/7/25 17:44, Kris Van Hees wrote: > > Kernels prior to 5.6.0 pass 3 arguments (derived from the NFS hdr) > > to the nfs_initiate_read raw tracepoint, whereas kernels as of 5.6.0 > > pass just the NFS hdr. > > Is the same true of write?? If so, then maybe say so and point out that what > we're really doing is changing the handling of nfs "start" while leaving nfs > "done" alone...? that would correspond more closely to what is happening in > the code, which talks of start and done. Yes, and the code handles that also. So yes, should have mentioned write also. Mea culpa. > > Signed-off-by: Kris Van Hees > > --- > > libdtrace/dt_prov_io.c | 127 +++++++++++++++++++++++++++++++++++------ > > 1 file changed, 108 insertions(+), 19 deletions(-) > > > > diff --git a/libdtrace/dt_prov_io.c b/libdtrace/dt_prov_io.c > > @@ -155,12 +147,109 @@ static void deref_r3(dt_irlist_t *dlp, uint_t exitlbl, int addend, int width, > > +/* > > + * For NFS events, we have to construct a fake struct bio, which we have to > > + * populate from the inode (arg0) and hdr->good_bytes (arg2) arguments the > > + * underlying probe provides. > > + */ > > +static void io_nfs_args_v1(dt_pcb_t *pcb, dt_irlist_t *dlp, uint_t exitlbl, > > + const char *prb, const char *uprb) > > +{ > > + int off; > > + size_t siz; > > + > > + /* > > + * Determine the various sizes and offsets we want. > > + * > > + * // Access these fields relative to &bio. > > + * struct bio bio = { > > + * .bi_opf = ..., > > + * .bi_iter.bi_size = ..., // struct bvec_iter bi_iter > > + * .bi_iter.bi_sector = ..., > > + * .bi_bdev = 0, // -or- .bi_disk = 0 > > + * }; > > + * > > + * // Access these fields relative to hdr. > > + * struct nfs_pgio_header *hdr; > > + * ... = hdr->res.count; // struct nfs_pgio_res res > > + */ > > + > > + /* > > + * Declare the -io-bio variable and store its address in %r6. > > + */ > > + dt_cg_tramp_decl_var(pcb, &v_bio); > > + dt_cg_tramp_get_var(pcb, "this->-io-bio", 1, BPF_REG_6); > > + > > + /* Fill in bi_opf */ > > + off = dt_cg_ctf_offsetof("struct bio", "bi_opf", &siz, 0); > > + siz = bpf_ldst_size(siz, 1); > > + if (strstr(uprb, "read")) > > + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, REQ_OP_READ)); > > + else > > + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, REQ_OP_WRITE)); > > + > > + /* > > + * bio.bi_iter.bi_size = hdr->foo.count; > > If "v1" is broken out, then this hdr->foo.count no longer makes sense.? > Plus, the comment is more or less superseded by the following two comment > lines. > > Or, mimic how the comments are handled below for inode. Yes, clean up will be needed. > > + * > > + * For the 'start' probe, count is arg2 > > + * For the 'done' probe, count is hdr->res.count (hdr in arg1) > > + */ > > + if (strcmp(prb, "start") == 0) { > > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(2))); > > + } else { > > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(1))); > > + off = dt_cg_ctf_offsetof("struct nfs_pgio_header", "res", NULL, 0) > > + + dt_cg_ctf_offsetof("struct nfs_pgio_res", "count", &siz, 0); > > + deref_r3(dlp, exitlbl, off, siz, BPF_REG_0); > > + } > > + > > + off = dt_cg_ctf_offsetof("struct bio", "bi_iter", NULL, 0) > > + + dt_cg_ctf_offsetof("struct bvec_iter", "bi_size", &siz, 0); > > + siz = bpf_ldst_size(siz, 1); > > + emit(dlp, BPF_STORE(siz, BPF_REG_6, off, BPF_REG_0)); > > + > > + /* > > + * bio.bi_iter.bi_sector = inode; > > + */ > > + if (strcmp(prb, "start") == 0) { > > + /* inode is arg0 */ > > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(0))); > > + } else { > > + /* use hdr->inode, hdr is arg1 */ > > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(1))); > > + > > + off = dt_cg_ctf_offsetof("struct nfs_pgio_header", "inode", &siz, 0); > > + deref_r3(dlp, exitlbl, off, siz, BPF_REG_3); > > + } > > + > > + off = dt_cg_ctf_offsetof("struct nfs_inode", "fileid", &siz, 0) > > + - dt_cg_ctf_offsetof("struct nfs_inode", "vfs_inode", NULL, 0); > > + deref_r3(dlp, exitlbl, off, siz, BPF_REG_0); > > + > > + off = dt_cg_ctf_offsetof("struct bio", "bi_iter", NULL, 0) > > + + dt_cg_ctf_offsetof("struct bvec_iter", "bi_sector", &siz, 0); > > + siz = bpf_ldst_size(siz, 1); > > + emit(dlp, BPF_STORE(siz, BPF_REG_6, off, BPF_REG_0)); > > + > > + /* > > + * bio.bi_bdev = 0; > > + */ > > + off = dt_cg_ctf_offsetof("struct bio", "bi_bdev", &siz, 1); > > + if (off == -1) > > + off = dt_cg_ctf_offsetof("struct bio", "bi_disk", &siz, 0); > > + siz = bpf_ldst_size(siz, 1); > > + emit(dlp, BPF_STORE_IMM(siz, BPF_REG_6, off, 0)); > > + > > + /* Store a pointer to the fake bio in arg0. */ > > + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_6)); > > +} From kris.van.hees at oracle.com Thu Jan 9 18:18:43 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 9 Jan 2025 13:18:43 -0500 Subject: [DTrace-devel] [PATCH] io: adjust io provider for NFS tracepoint variants In-Reply-To: <87ed1dh73n.fsf@esperi.org.uk> References: <474ca7db-5d3c-0426-7b17-fb04043544c5@oracle.com> <87ed1dh73n.fsf@esperi.org.uk> Message-ID: On Wed, Jan 08, 2025 at 11:34:36AM +0000, Nick Alcock wrote: > On 8 Jan 2025, Eugene Loh uttered the following: > > > You already have a R-b, it seems the code is right (woo hoo! cool), and we're trying to get a release out the door.? But here are my > > "late to the party" comments.? Feel free to ignore. > > Ditto :) > > > The names v1 and v2 strike me as funny;? they just make up new numbers.? Not a big deal, but ideally the names might more closely > > reflect the actual version changes we're tracking. > > Agreed. See my rationale in my reply to Eugene. > > Breaking the function out into a new "v1" version is some unneeded copy-and-paste code bloat, I think.? The function is kind of > > large and the only difference between v1 and v2 is I guess in the two, relatively short, "start" sections.? So, keeping this stuff > > as one function -- with extra logic in the two "start" sections -- might be more compact and clearer than having two rather similar > > functions. > > Agreed, but more generally it seems we are growing increasingly many > fairly similar fake bio functions in the io provider: with this I think > we're up to three. Maybe it's time to refactor some of this into some > sort of shared fake bio machinery? Certainly if we grow more I think we > should (and given the number of network filesystems, that seems quite > likely to happen). The trouble is that they are also sufficiently different, and with how we need to generate code to trace down pointer chains etc in various ways, consolidated code can get more convoluted and hard to read. It will remain a balance between sharing code with possible lack of clarity and more complexity, or code duplication with more clarity and reduces complexity. Sometimes it gets hard to judge which is better, but this certainly can be looked at and we can go from there. > > On 1/7/25 17:44, Kris Van Hees wrote: > >> Kernels prior to 5.6.0 pass 3 arguments (derived from the NFS hdr) > >> to the nfs_initiate_read raw tracepoint, whereas kernels as of 5.6.0 > >> pass just the NFS hdr. > > > > Is the same true of write?? If so, then maybe say so and point out that what we're really doing is changing the handling of nfs > > "start" while leaving nfs "done" alone...? that would correspond more closely to what is happening in the code, which talks of start > > and done. > > Good thinkiing. That would be commit > 5bb2a7cb9fe58d2b1efedd6058d442c7871c45ec ("NFS: Clean up generic > writeback tracepoints"), also by Trond, also first landing in 5.6-rc1. > Same sort of thing. From kris.van.hees at oracle.com Thu Jan 9 19:12:02 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 9 Jan 2025 14:12:02 -0500 Subject: [DTrace-devel] [PATCH 6/6] Add support for pid function "-" with absolute offset In-Reply-To: <20241220222716.18511-6-eugene.loh@oracle.com> References: <20241220222716.18511-1-eugene.loh@oracle.com> <20241220222716.18511-6-eugene.loh@oracle.com> Message-ID: A first early comment. You are changing the existing implementation of this quite a bit so I am still tracing through it a bit to understand it all :) Good stuff though. On Fri, Dec 20, 2024 at 05:27:16PM -0500, eugene.loh--- via DTrace-devel wrote: > From: Eugene Loh > > Signed-off-by: Eugene Loh > --- > include/dtrace/pid.h | 1 + > libdtrace/dt_pid.c | 75 +++++++++++++----- > libdtrace/dt_prov_uprobe.c | 2 +- > test/unittest/pid/tst.dash.r | 1 + > test/unittest/pid/tst.dash.sh | 118 ++++++++++++++++++++++++++++ > test/unittest/usdt/tst.pidprobes.sh | 18 ++++- > 6 files changed, 192 insertions(+), 23 deletions(-) > create mode 100644 test/unittest/pid/tst.dash.r > create mode 100755 test/unittest/pid/tst.dash.sh > > diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h > index c53e60047..ad0aad9d8 100644 > --- a/include/dtrace/pid.h > +++ b/include/dtrace/pid.h > @@ -47,6 +47,7 @@ typedef struct pid_probespec { > /* > * Fields below this point do not apply to underlying probes. > */ > + int pps_absoff; /* use "-" for overlying probe function */ Why use this? All you do with it is record that func is "-", and then later in the pid provider, you actually use that to force the function name in the probe description to be "-". But that function name in the probe desc is (in the pid provider) already coming from pps_fun, and the code was already assigning func to pps_fun, so it would be "-" anyway. So the pps_absoff seems to serve no purpose, and you could just rely on pps_fun being "-" when needed. > pid_t pps_pid; /* task PID */ > uint64_t pps_nameoff; /* offset to use for name */ > } pid_probespec_t; > diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c > index b8bbb0396..dae499422 100644 > --- a/libdtrace/dt_pid.c > +++ b/libdtrace/dt_pid.c > @@ -155,7 +155,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) > uint_t nmatches = 0; > ulong_t sz; > int glob, rc = 0; > - int isdash = strcmp("-", func) == 0; > pid_t pid; > > /* > @@ -182,8 +181,50 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) > psp->pps_fun = (char *) func; > psp->pps_nameoff = 0; > psp->pps_off = symp->st_value - pp->dpp_vaddr; > + psp->pps_absoff = 0; > > - if (!isdash && gmatch("return", pp->dpp_name)) { > + /* > + * The special function "-" means the probe name is an absolute > + * virtual address. > + */ > + if (strcmp("-", func) == 0) { > + char *end; > + GElf_Sym sym; > + > + off = strtoull(pp->dpp_name, &end, 16); > + if (*end != '\0') { > + rc = dt_pid_error(dtp, pcb, dpr, D_PROC_NAME, > + "'%s' is an invalid probe name", > + pp->dpp_name); > + goto out; > + } > + > + psp->pps_absoff = 1; > + psp->pps_nameoff = off; > + > + if (dt_Plookup_by_addr(dtp, pid, off, (const char **)&psp->pps_fun, &sym)) { > + rc = dt_pid_error(dtp, pcb, dpr, D_PROC_NAME, > + "failed to lookup 0x%lx in module '%s'", off, pp->dpp_mod); > + if (psp->pps_fun != func && psp->pps_fun != NULL) > + free(psp->pps_fun); > + goto out; > + } > + > + psp->pps_prb = (char*)pp->dpp_name; // make sure dt_prov_uprobe uses it > + psp->pps_off = off - sym.st_value; // make sure dt_prov_uprobe uses it // dump this > + psp->pps_off = off - pp->dpp_vaddr; // make sure dt_prov_uprobe uses it > + > + if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, DTPPT_OFFSETS) < 0) > + rc = dt_pid_error(dtp, pcb, dpr, D_PROC_CREATEFAIL, > + "failed to create probes at '%s+0x%llx': %s", > + func, (unsigned long long)off, dtrace_errmsg(dtp, dtrace_errno(dtp))); > + else > + pp->dpp_nmatches++; > + free(psp->pps_fun); > + goto out; > + } > + > + if (gmatch("return", pp->dpp_name)) { > if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, DTPPT_RETURN) < 0) { > rc = dt_pid_error( > dtp, pcb, dpr, D_PROC_CREATEFAIL, > @@ -195,7 +236,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) > nmatches++; > } > > - if (!isdash && gmatch("entry", pp->dpp_name)) { > + if (gmatch("entry", pp->dpp_name)) { > if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, DTPPT_ENTRY) < 0) { > rc = dt_pid_error( > dtp, pcb, dpr, D_PROC_CREATEFAIL, > @@ -240,7 +281,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) > } > > nmatches++; > - } else if (glob && !isdash) { > + } else if (glob) { > #if defined(__amd64) > /* > * We need to step through the instructions to find their > @@ -449,31 +490,26 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj) > else > pp->dpp_obj++; > > + /* > + * If it is the special function "-", cut to dt_pid_per_sym() now. > + */ > + if (strcmp("-", pp->dpp_func) == 0) > + return dt_pid_per_sym(pp, &sym, pp->dpp_func); > + > /* > * If pp->dpp_func contains any globbing meta-characters, we need > * to iterate over the symbol table and compare each function name > * against the pattern. > */ > if (!strisglob(pp->dpp_func)) { > - /* > - * If we fail to lookup the symbol, try interpreting the > - * function as the special "-" function that indicates that the > - * probe name should be interpreted as a absolute virtual > - * address. If that fails and we were matching a specific > + /* If we are matching a specific > * function in a specific module, report the error, otherwise > * just fail silently in the hopes that some other object will > * contain the desired symbol. > */ > if (dt_Pxlookup_by_name(dtp, pid, pp->dpp_lmid, obj, > pp->dpp_func, &sym, NULL) != 0) { > - if (strcmp("-", pp->dpp_func) == 0) { > - sym.st_name = 0; > - sym.st_info = > - GELF_ST_INFO(STB_LOCAL, STT_FUNC); > - sym.st_other = 0; > - sym.st_value = 0; > - sym.st_size = Pelf64(pp->dpp_pr) ? -1ULL : -1U; > - } else if (!strisglob(pp->dpp_mod)) { > + if (!strisglob(pp->dpp_mod)) { > return dt_pid_error( > dtp, pcb, dpr, D_PROC_FUNC, > "failed to lookup '%s' in module '%s'", > @@ -647,9 +683,10 @@ dt_pid_create_pid_probes_proc(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, > if (strcmp(pp.dpp_func, "-") == 0) { > const prmap_t *aout, *pmp; > > - if (pdp->mod[0] == '\0') { > - pp.dpp_mod = pdp->mod; > + if (strcmp(pp.dpp_mod, "*") == 0) { > + /* Tolerate two glob cases: "" and "*". */ > pdp->mod = "a.out"; > + pp.dpp_mod = pdp->mod; > } else if (strisglob(pp.dpp_mod) || > (aout = dt_Pname_to_map(dtp, pid, "a.out")) == NULL || > (pmp = dt_Pname_to_map(dtp, pid, pp.dpp_mod)) == NULL || > diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c > index acf1c914f..ae4b262ac 100644 > --- a/libdtrace/dt_prov_uprobe.c > +++ b/libdtrace/dt_prov_uprobe.c > @@ -735,7 +735,7 @@ static int provide_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp, > pd.id = DTRACE_IDNONE; > pd.prv = prv; > pd.mod = psp->pps_mod; > - pd.fun = psp->pps_fun; > + pd.fun = psp->pps_absoff ? "-" : psp->pps_fun; > pd.prb = prb; > > /* Get (or create) the provider for the PID of the probe. */ > diff --git a/test/unittest/pid/tst.dash.r b/test/unittest/pid/tst.dash.r > new file mode 100644 > index 000000000..2e9ba477f > --- /dev/null > +++ b/test/unittest/pid/tst.dash.r > @@ -0,0 +1 @@ > +success > diff --git a/test/unittest/pid/tst.dash.sh b/test/unittest/pid/tst.dash.sh > new file mode 100755 > index 000000000..996b79f4f > --- /dev/null > +++ b/test/unittest/pid/tst.dash.sh > @@ -0,0 +1,118 @@ > +#!/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 > + > +DIRNAME=$tmpdir/pid-dash.$$.$RANDOM > +mkdir $DIRNAME > +cd $DIRNAME > + > +# Make trigger program. > + > +cat << EOF > main.c > +int foo0(int i) { > + int j, k; > + > + j = i ^ 1; k = j ^ 1; i = k ^ 1; > + j = i ^ 1; k = j ^ 1; i = k ^ 1; > + j = i ^ 1; k = j ^ 1; i = k ^ 1; > + > + return i; > +} > +int foo1(int i) { > + int j, k; > + > + j = i ^ 1; k = j ^ 1; i = k ^ 1; > + j = i ^ 1; k = j ^ 1; i = k ^ 1; > + j = i ^ 1; k = j ^ 1; i = k ^ 1; > + > + return i; > +} > +int foo2(int i) { > + int j, k; > + > + j = i ^ 1; k = j ^ 1; i = k ^ 1; > + j = i ^ 1; k = j ^ 1; i = k ^ 1; > + j = i ^ 1; k = j ^ 1; i = k ^ 1; > + > + return i; > +} > +int main(int c, char **v) { > + int i = 0; > + > + i = foo0(i) ^ i; > + i = foo1(i) ^ i; > + i = foo2(i) ^ i; > + > + return i; > +} > +EOF > + > +gcc main.c > +if [ $? -ne 0 ]; then > + echo ERROR compile > + exit 1 > +fi > + > +# Loop over functions in the program. > + > +for func in foo0 foo1 foo2 main; do > + # For each function, get the absolute and relative > + # (to the function) address of some instruction in > + # the function. > + read ABS REL <<< `objdump -d a.out | awk ' > + # Look for the function. > + /^[0-9a-f]* <'$func'>:$/ { > + > + # Get the first instruction and note the base address of the function. > + getline; sub(":", ""); base = strtonum("0x"$1); > + > + # Get the next instruction. > + getline; > + > + # Get the next instruction. Note its PC. > + getline; sub(":", ""); pc = strtonum("0x"$1); > + > + # Print the address, both absolute and relative. > + printf("%x %x\n", pc, pc - base); > + exit(0); > + }'` > + > + # Write the expected output to the compare file. > + echo got $ABS $func:$REL >> dtrace.exp > + echo got $ABS "-":$ABS >> dtrace.exp > + > + # Write the actual dtrace output to the output file. > + # Specify the pid probe with both relative and absolute > + # forms. > + for probe in $func:$REL "-:$ABS"; do > + $dtrace -c ./a.out -o dtrace.out -qn ' > + pid$target:a.out:'$probe' > + { printf("got %x %s:%s", uregs[R_PC], probefunc, > + probename); }' > + if [ $? -ne 0 ]; then > + echo ERROR: dtrace > + cat dtrace.out > + exit 1 > + fi > + done > +done > + > +# Check results. > + > +if ! diff -q dtrace.exp dtrace.out; then > + echo ERROR: > + echo "==== expected" > + cat dtrace.exp > + echo "==== actual" > + cat dtrace.out > + exit 1 > +fi > + > +echo success > +exit 0 > diff --git a/test/unittest/usdt/tst.pidprobes.sh b/test/unittest/usdt/tst.pidprobes.sh > index 54444d49b..e3e4e2043 100755 > --- a/test/unittest/usdt/tst.pidprobes.sh > +++ b/test/unittest/usdt/tst.pidprobes.sh > @@ -121,7 +121,13 @@ fi > pcs=`awk '{print strtonum("0x"$1)}' disasm_foo.txt` > pc0=`echo $pcs | awk '{print $1}'` > > -# Run dtrace. > +# Construct D script: add a pid$pid::-:$absoff probe for each PC in foo. > + > +for pc in $pcs; do > + printf 'p*d$target::-:%x,\n' $pc >> pidprobes.d > +done > + > +# Construct D script: add a glob for all pid and USDT pyramid probes in foo. > > cat >> pidprobes.d <<'EOF' > p*d$target::foo: > @@ -130,6 +136,8 @@ p*d$target::foo: > } > EOF > > +# Construct D script: add a glob for all USDT pyramid probes, dumping args. > + > if [[ -n $usdt ]]; then > echo 'pyramid$target::foo: {' >> pidprobes.d > > @@ -141,6 +149,8 @@ if [[ -n $usdt ]]; then > echo '}' >> pidprobes.d > fi > > +# Run dtrace. > + > $dtrace $dt_flags -q -c ./main -o dtrace.out -s pidprobes.d > main.out2 > if [ $? -ne 0 ]; then > echo "failed to run dtrace" >&2 > @@ -286,14 +296,16 @@ fi > # - a blank line > # - pid entry > # - pid return > -# - pid offset > +# - pid offset (relative -- that is, pid$pid:main:foo:$reloff) > +# - pid offset (absolute -- that is, pid$pid:main:-:$absoff) > # - two USDT probes (ignore is-enabled probes) > > echo > dtrace.out.expected > -printf "$pid pid$pid:main:foo:entry %x\n" $pc0 >> 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 > + printf "$pid pid$pid:main:-:%x %x\n" $pc $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", $2);}' >> dtrace.out.expected > -- > 2.43.5 > > > _______________________________________________ > DTrace-devel mailing list > DTrace-devel at oss.oracle.com > https://oss.oracle.com/mailman/listinfo/dtrace-devel From kris.van.hees at oracle.com Thu Jan 9 19:14:15 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 9 Jan 2025 14:14:15 -0500 Subject: [DTrace-devel] [PATCH 1/6] Remove unused dpp_pc and dpp_size In-Reply-To: <20241220222716.18511-1-eugene.loh@oracle.com> References: <20241220222716.18511-1-eugene.loh@oracle.com> Message-ID: On Fri, Dec 20, 2024 at 05:27:11PM -0500, eugene.loh at oracle.com wrote: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees > --- > libdtrace/dt_pid.c | 2 -- > 1 file changed, 2 deletions(-) > > diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c > index fd94a0706..2331d1aa7 100644 > --- a/libdtrace/dt_pid.c > +++ b/libdtrace/dt_pid.c > @@ -53,9 +53,7 @@ typedef struct dt_pid_probe { > dev_t dpp_dev; > ino_t dpp_inum; > const char *dpp_fname; > - uintptr_t dpp_pc; > uintptr_t dpp_vaddr; > - size_t dpp_size; > Lmid_t dpp_lmid; > uint_t dpp_nmatches; > GElf_Sym dpp_last; > -- > 2.43.5 > From kris.van.hees at oracle.com Thu Jan 9 19:17:19 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 9 Jan 2025 14:17:19 -0500 Subject: [DTrace-devel] [PATCH 4/6] Remove unused function arg In-Reply-To: <20241220222716.18511-4-eugene.loh@oracle.com> References: <20241220222716.18511-1-eugene.loh@oracle.com> <20241220222716.18511-4-eugene.loh@oracle.com> Message-ID: On Fri, Dec 20, 2024 at 05:27:14PM -0500, eugene.loh--- via DTrace-devel wrote: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees ... merging is pending because it depends on earier patches yet to be reviewed. > --- > libdtrace/dt_pid.c | 12 +++++------- > 1 file changed, 5 insertions(+), 7 deletions(-) > > diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c > index e57478450..b8bbb0396 100644 > --- a/libdtrace/dt_pid.c > +++ b/libdtrace/dt_pid.c > @@ -104,7 +104,7 @@ dt_pid_error(dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr, > > static int > dt_pid_create_one_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, > - pid_probespec_t *psp, const GElf_Sym *symp, pid_probetype_t type) > + pid_probespec_t *psp, pid_probetype_t type) > { > const dt_provider_t *pvp = dtp->dt_prov_pid; > > @@ -184,8 +184,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) > psp->pps_off = symp->st_value - pp->dpp_vaddr; > > if (!isdash && gmatch("return", pp->dpp_name)) { > - if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, symp, > - DTPPT_RETURN) < 0) { > + if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, DTPPT_RETURN) < 0) { > rc = dt_pid_error( > dtp, pcb, dpr, D_PROC_CREATEFAIL, > "failed to create return probe for '%s': %s", > @@ -197,8 +196,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) > } > > if (!isdash && gmatch("entry", pp->dpp_name)) { > - if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, symp, > - DTPPT_ENTRY) < 0) { > + if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, DTPPT_ENTRY) < 0) { > rc = dt_pid_error( > dtp, pcb, dpr, D_PROC_CREATEFAIL, > "failed to create entry probe for '%s': %s", > @@ -232,7 +230,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) > psp->pps_nameoff = off; > psp->pps_off = symp->st_value - pp->dpp_vaddr + off; > if (dt_pid_create_one_probe(pp->dpp_pr, dtp, > - psp, symp, DTPPT_OFFSETS) < 0) { > + psp, DTPPT_OFFSETS) < 0) { > rc = dt_pid_error( > dtp, pcb, dpr, D_PROC_CREATEFAIL, > "failed to create probes at '%s+0x%llx': %s", > @@ -363,7 +361,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) > psp->pps_nameoff = off; > psp->pps_off = symp->st_value - pp->dpp_vaddr + off; > if (dt_pid_create_one_probe(pp->dpp_pr, dtp, > - psp, symp, DTPPT_OFFSETS) >= 0) > + psp, DTPPT_OFFSETS) >= 0) > nmatches++; > } > > -- > 2.43.5 > > > _______________________________________________ > DTrace-devel mailing list > DTrace-devel at oss.oracle.com > https://oss.oracle.com/mailman/listinfo/dtrace-devel From kris.van.hees at oracle.com Thu Jan 9 19:21:51 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 9 Jan 2025 14:21:51 -0500 Subject: [DTrace-devel] [PATCH 3/6] Simplify references to dtp In-Reply-To: <20241220222716.18511-3-eugene.loh@oracle.com> References: <20241220222716.18511-1-eugene.loh@oracle.com> <20241220222716.18511-3-eugene.loh@oracle.com> Message-ID: On Fri, Dec 20, 2024 at 05:27:13PM -0500, eugene.loh at oracle.com wrote: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees > --- > libdtrace/dt_pid.c | 17 ++++++++--------- > 1 file changed, 8 insertions(+), 9 deletions(-) > > diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c > index 27cd7d13f..e57478450 100644 > --- a/libdtrace/dt_pid.c > +++ b/libdtrace/dt_pid.c > @@ -231,7 +231,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) > > psp->pps_nameoff = off; > psp->pps_off = symp->st_value - pp->dpp_vaddr + off; > - if (dt_pid_create_one_probe(pp->dpp_pr, pp->dpp_dtp, > + if (dt_pid_create_one_probe(pp->dpp_pr, dtp, > psp, symp, DTPPT_OFFSETS) < 0) { > rc = dt_pid_error( > dtp, pcb, dpr, D_PROC_CREATEFAIL, > @@ -362,7 +362,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) > > psp->pps_nameoff = off; > psp->pps_off = symp->st_value - pp->dpp_vaddr + off; > - if (dt_pid_create_one_probe(pp->dpp_pr, pp->dpp_dtp, > + if (dt_pid_create_one_probe(pp->dpp_pr, dtp, > psp, symp, DTPPT_OFFSETS) >= 0) > nmatches++; > } > @@ -434,7 +434,7 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj) > if (obj == NULL) > return 0; > > - dt_Plmid(pp->dpp_dtp, pid, pmp->pr_vaddr, &pp->dpp_lmid); > + dt_Plmid(dtp, pid, pmp->pr_vaddr, &pp->dpp_lmid); > > pp->dpp_dev = pmp->pr_dev; > pp->dpp_inum = pmp->pr_inum; > @@ -466,7 +466,7 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj) > * just fail silently in the hopes that some other object will > * contain the desired symbol. > */ > - if (dt_Pxlookup_by_name(pp->dpp_dtp, pid, pp->dpp_lmid, obj, > + if (dt_Pxlookup_by_name(dtp, pid, pp->dpp_lmid, obj, > pp->dpp_func, &sym, NULL) != 0) { > if (strcmp("-", pp->dpp_func) == 0) { > sym.st_name = 0; > @@ -496,17 +496,17 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj) > * dynamically rewritten, and, so, inherently dicey to > * instrument. > */ > - if (dt_Pwritable_mapping(pp->dpp_dtp, pid, sym.st_value)) > + if (dt_Pwritable_mapping(dtp, pid, sym.st_value)) > return 0; > // FIXME: why are we changing to a spelling that differs from what the user asked for? > - dt_Plookup_by_addr(pp->dpp_dtp, pid, sym.st_value, > + dt_Plookup_by_addr(dtp, pid, sym.st_value, > &pp->dpp_func, &sym); > > return dt_pid_per_sym(pp, &sym, pp->dpp_func); > } else { > uint_t nmatches = pp->dpp_nmatches; > > - if (dt_Psymbol_iter_by_addr(pp->dpp_dtp, pid, obj, PR_SYMTAB, > + if (dt_Psymbol_iter_by_addr(dtp, pid, obj, PR_SYMTAB, > BIND_ANY | TYPE_FUNC, > dt_pid_sym_filt, pp) == 1) > return 1; > @@ -516,8 +516,7 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj) > * If we didn't match anything in the PR_SYMTAB, try > * the PR_DYNSYM. > */ > - if (dt_Psymbol_iter_by_addr( > - pp->dpp_dtp, pid, obj, > + if (dt_Psymbol_iter_by_addr(dtp, pid, obj, > PR_DYNSYM, BIND_ANY | TYPE_FUNC, > dt_pid_sym_filt, pp) == 1) > return 1; > -- > 2.43.5 > From eugene.loh at oracle.com Thu Jan 9 20:52:28 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Thu, 9 Jan 2025 15:52:28 -0500 Subject: [DTrace-devel] [PATCH 6/6] Add support for pid function "-" with absolute offset In-Reply-To: References: <20241220222716.18511-1-eugene.loh@oracle.com> <20241220222716.18511-6-eugene.loh@oracle.com> Message-ID: <68af528d-8dbd-f081-835a-d92b42e3045e@oracle.com> On 1/9/25 14:12, Kris Van Hees wrote: > On Fri, Dec 20, 2024 at 05:27:16PM -0500, eugene.loh--- via DTrace-devel wrote: >> diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h >> @@ -47,6 +47,7 @@ typedef struct pid_probespec { >> /* >> * Fields below this point do not apply to underlying probes. >> */ >> + int pps_absoff; /* use "-" for overlying probe function */ > Why use this? All you do with it is record that func is "-", and then later > in the pid provider, you actually use that to force the function name in the > probe description to be "-". But that function name in the probe desc is (in > the pid provider) already coming from pps_fun, and the code was already > assigning func to pps_fun, so it would be "-" anyway. So the pps_absoff seems > to serve no purpose, and you could just rely on pps_fun being "-" when needed. Yeah, good point.? Let me see if I can remember/understand/explain what's going on here. In essence, the problem is we have to pass two function names:? "-" (for the overlying probe) and the actual function name (for the underlying probe);? up until now, they were both the same.? I tossed around different ideas for this.? E.g., pass two function names in. Or, get the actual function name inside dt_prov_uprobe.? It seemed to make most sense (given the alternatives) to pass in the actual function name and add this flag to say when the overlying probe's function name should be "-".? Does that make sense? Note that pps_fun is not "-".? Although we set it to func ("-"), the code that processes this case then fills pps_fun in with the actual function name.? Again, one option is not to do this until dt_prov_uprobe.c, but that introduces some other hassles. >> pid_t pps_pid; /* task PID */ >> uint64_t pps_nameoff; /* offset to use for name */ >> } pid_probespec_t; >> diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c >> @@ -182,8 +181,50 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) >> psp->pps_fun = (char *) func; >> psp->pps_nameoff = 0; >> psp->pps_off = symp->st_value - pp->dpp_vaddr; >> + psp->pps_absoff = 0; >> >> - if (!isdash && gmatch("return", pp->dpp_name)) { >> + /* >> + * The special function "-" means the probe name is an absolute >> + * virtual address. >> + */ >> + if (strcmp("-", func) == 0) { >> + char *end; >> + GElf_Sym sym; >> + >> + off = strtoull(pp->dpp_name, &end, 16); >> + >> + psp->pps_absoff = 1; >> + psp->pps_nameoff = off; >> + >> + if (dt_Plookup_by_addr(dtp, pid, off, (const char **)&psp->pps_fun, &sym)) { >> + rc = dt_pid_error(dtp, pcb, dpr, D_PROC_NAME, >> + "failed to lookup 0x%lx in module '%s'", off, pp->dpp_mod); >> + if (psp->pps_fun != func && psp->pps_fun != NULL) >> + free(psp->pps_fun); >> + goto out; >> + } >> + >> + psp->pps_prb = (char*)pp->dpp_name; // make sure dt_prov_uprobe uses it >> + psp->pps_off = off - sym.st_value; // make sure dt_prov_uprobe uses it // dump this >> + psp->pps_off = off - pp->dpp_vaddr; // make sure dt_prov_uprobe uses it >> + >> + if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, DTPPT_OFFSETS) < 0) >> + rc = dt_pid_error(dtp, pcb, dpr, D_PROC_CREATEFAIL, >> + "failed to create probes at '%s+0x%llx': %s", >> + func, (unsigned long long)off, dtrace_errmsg(dtp, dtrace_errno(dtp))); >> + else >> + pp->dpp_nmatches++; >> + free(psp->pps_fun); >> + goto out; >> + } >> + >> + if (gmatch("return", pp->dpp_name)) { >> if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, DTPPT_RETURN) < 0) { >> rc = dt_pid_error( >> dtp, pcb, dpr, D_PROC_CREATEFAIL, >> diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c >> index acf1c914f..ae4b262ac 100644 >> --- a/libdtrace/dt_prov_uprobe.c >> +++ b/libdtrace/dt_prov_uprobe.c >> @@ -735,7 +735,7 @@ static int provide_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp, >> pd.id = DTRACE_IDNONE; >> pd.prv = prv; >> pd.mod = psp->pps_mod; >> - pd.fun = psp->pps_fun; >> + pd.fun = psp->pps_absoff ? "-" : psp->pps_fun; >> pd.prb = prb; >> >> /* Get (or create) the provider for the PID of the probe. */ From eugene.loh at oracle.com Thu Jan 9 21:00:42 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Thu, 9 Jan 2025 16:00:42 -0500 Subject: [DTrace-devel] [PATCH 6/6] Add support for pid function "-" with absolute offset In-Reply-To: <68af528d-8dbd-f081-835a-d92b42e3045e@oracle.com> References: <20241220222716.18511-1-eugene.loh@oracle.com> <20241220222716.18511-6-eugene.loh@oracle.com> <68af528d-8dbd-f081-835a-d92b42e3045e@oracle.com> Message-ID: <17bc480b-3785-7b7e-9df9-601d65038df8@oracle.com> On 1/9/25 15:52, Eugene Loh wrote: > On 1/9/25 14:12, Kris Van Hees wrote: > >> On Fri, Dec 20, 2024 at 05:27:16PM -0500, eugene.loh--- via >> DTrace-devel wrote: >>> diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h >>> @@ -47,6 +47,7 @@ typedef struct pid_probespec { >>> ????? /* >>> ?????? * Fields below this point do not apply to underlying probes. >>> ?????? */ >>> +??? int pps_absoff;??????????????? /* use "-" for overlying probe >>> function */ >> Why use this?? All you do with it is record that func is "-", and >> then later >> in the pid provider, you actually use that to force the function name >> in the >> probe description to be "-".? But that function name in the probe >> desc is (in >> the pid provider) already coming from pps_fun, and the code was already >> assigning func to pps_fun, so it would be "-" anyway.? So the >> pps_absoff seems >> to serve no purpose, and you could just rely on pps_fun being "-" >> when needed. > > Yeah, good point.? Let me see if I can remember/understand/explain > what's going on here. > > In essence, the problem is we have to pass two function names: "-" > (for the overlying probe) and the actual function name (for the > underlying probe);? up until now, they were both the same.? I tossed > around different ideas for this.? E.g., pass two function names in. > Or, get the actual function name inside dt_prov_uprobe. It seemed to > make most sense (given the alternatives) to pass in the actual > function name and add this flag to say when the overlying probe's > function name should be "-".? Does that make sense? > > Note that pps_fun is not "-".? Although we set it to func ("-"), the > code that processes this case then fills pps_fun in with the actual > function name.? Again, one option is not to do this until > dt_prov_uprobe.c, but that introduces some other hassles. Hmm.? Having said all that, maybe another (better?!) way of solving this problem is to add another probe type to pid_probetype_t.? Maybe DTPPT_ABSOFFSETS.? After all, we already have this problem of a "special" name for the overlying probe while requiring the "real" name for the underlying probe:? we have that problem for probe names.? There, we solve the problem by checking the pid_probetype_t.? So maybe that same approach should be used here, for probe function. Let me know.? If you agree/prefer, I can revise the patch. > >>> ????? pid_t pps_pid;??????????????? /* task PID */ >>> ????? uint64_t pps_nameoff;??????????? /* offset to use for name */ >>> ? } pid_probespec_t; >>> diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c >>> @@ -182,8 +181,50 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const >>> GElf_Sym *symp, const char *func) >>> ????? psp->pps_fun = (char *) func; >>> ????? psp->pps_nameoff = 0; >>> ????? psp->pps_off = symp->st_value - pp->dpp_vaddr; >>> +??? psp->pps_absoff = 0; >>> ? -??? if (!isdash && gmatch("return", pp->dpp_name)) { >>> +??? /* >>> +???? * The special function "-" means the probe name is an absolute >>> +???? * virtual address. >>> +???? */ >>> +??? if (strcmp("-", func) == 0) { >>> +??????? char *end; >>> +??????? GElf_Sym sym; >>> + >>> +??????? off = strtoull(pp->dpp_name, &end, 16); >>> + >>> +??????? psp->pps_absoff = 1; >>> +??????? psp->pps_nameoff = off; >>> + >>> +??????? if (dt_Plookup_by_addr(dtp, pid, off, (const char >>> **)&psp->pps_fun, &sym)) { >>> +??????????? rc = dt_pid_error(dtp, pcb, dpr, D_PROC_NAME, >>> +???????????????? "failed to lookup 0x%lx in module '%s'", off, >>> pp->dpp_mod); >>> +??????????? if (psp->pps_fun != func && psp->pps_fun != NULL) >>> +??????????????? free(psp->pps_fun); >>> +??????????? goto out; >>> +??????? } >>> + >>> +??????? psp->pps_prb = (char*)pp->dpp_name;? // make sure >>> dt_prov_uprobe uses it >>> +??????? psp->pps_off = off - sym.st_value;?? // make sure >>> dt_prov_uprobe uses it // dump this >>> +??????? psp->pps_off = off - pp->dpp_vaddr;? // make sure >>> dt_prov_uprobe uses it >>> + >>> +??????? if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, >>> DTPPT_OFFSETS) < 0) >>> +??????????? rc = dt_pid_error(dtp, pcb, dpr, D_PROC_CREATEFAIL, >>> +??????????????? "failed to create probes at '%s+0x%llx': %s", >>> +??????????????? func, (unsigned long long)off, dtrace_errmsg(dtp, >>> dtrace_errno(dtp))); >>> +??????? else >>> +??????????? pp->dpp_nmatches++; >>> +??????? free(psp->pps_fun); >>> +??????? goto out; >>> +??? } >>> + >>> +??? if (gmatch("return", pp->dpp_name)) { >>> ????????? if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, >>> DTPPT_RETURN) < 0) { >>> ????????????? rc = dt_pid_error( >>> ????????????????? dtp, pcb, dpr, D_PROC_CREATEFAIL, >>> diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c >>> index acf1c914f..ae4b262ac 100644 >>> --- a/libdtrace/dt_prov_uprobe.c >>> +++ b/libdtrace/dt_prov_uprobe.c >>> @@ -735,7 +735,7 @@ static int provide_probe(dtrace_hdl_t *dtp, >>> const pid_probespec_t *psp, >>> ????? pd.id = DTRACE_IDNONE; >>> ????? pd.prv = prv; >>> ????? pd.mod = psp->pps_mod; >>> -??? pd.fun = psp->pps_fun; >>> +??? pd.fun = psp->pps_absoff ? "-" : psp->pps_fun; >>> ????? pd.prb = prb; >>> ? ????? /* Get (or create) the provider for the PID of the probe. */ From kris.van.hees at oracle.com Fri Jan 10 05:07:36 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Fri, 10 Jan 2025 00:07:36 -0500 Subject: [DTrace-devel] [PATCH 6/6] Add support for pid function "-" with absolute offset In-Reply-To: <17bc480b-3785-7b7e-9df9-601d65038df8@oracle.com> References: <20241220222716.18511-1-eugene.loh@oracle.com> <20241220222716.18511-6-eugene.loh@oracle.com> <68af528d-8dbd-f081-835a-d92b42e3045e@oracle.com> <17bc480b-3785-7b7e-9df9-601d65038df8@oracle.com> Message-ID: On Thu, Jan 09, 2025 at 04:00:42PM -0500, Eugene Loh wrote: > On 1/9/25 15:52, Eugene Loh wrote: > > > On 1/9/25 14:12, Kris Van Hees wrote: > > > > > On Fri, Dec 20, 2024 at 05:27:16PM -0500, eugene.loh--- via > > > DTrace-devel wrote: > > > > diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h > > > > @@ -47,6 +47,7 @@ typedef struct pid_probespec { > > > > ????? /* > > > > ?????? * Fields below this point do not apply to underlying probes. > > > > ?????? */ > > > > +??? int pps_absoff;??????????????? /* use "-" for overlying > > > > probe function */ > > > Why use this?? All you do with it is record that func is "-", and > > > then later > > > in the pid provider, you actually use that to force the function > > > name in the > > > probe description to be "-".? But that function name in the probe > > > desc is (in > > > the pid provider) already coming from pps_fun, and the code was already > > > assigning func to pps_fun, so it would be "-" anyway.? So the > > > pps_absoff seems > > > to serve no purpose, and you could just rely on pps_fun being "-" > > > when needed. > > > > Yeah, good point.? Let me see if I can remember/understand/explain > > what's going on here. > > > > In essence, the problem is we have to pass two function names: "-" (for > > the overlying probe) and the actual function name (for the underlying > > probe);? up until now, they were both the same.? I tossed around > > different ideas for this.? E.g., pass two function names in. Or, get the > > actual function name inside dt_prov_uprobe. It seemed to make most sense > > (given the alternatives) to pass in the actual function name and add > > this flag to say when the overlying probe's function name should be > > "-".? Does that make sense? > > > > Note that pps_fun is not "-".? Although we set it to func ("-"), the > > code that processes this case then fills pps_fun in with the actual > > function name.? Again, one option is not to do this until > > dt_prov_uprobe.c, but that introduces some other hassles. Ok, I see what you mean... because we rely on underlying probes, we need to track the function name that the absolute offset falls in in order to be able to determine the underlying uprobe that the PID probe maps onto (especially since there might be another probe on it already). However, as far as I can see there is not really any need to have a function name on the underlying probe. After all, it is actually a uprobe that is identified by dev/inode/offset where offset is an offset into the mapping at dev/inode, i.e. not relative to any particular function at all. So, not having the function name associated with the underlying probe would make more sense than what we are doing now. And if we drop the function name from the underlying probe, we suddenly no longer need to carry it across for absolute offset probe, and this entire two-function name thing goes away. > Hmm.? Having said all that, maybe another (better?!) way of solving this > problem is to add another probe type to pid_probetype_t.? Maybe > DTPPT_ABSOFFSETS.? After all, we already have this problem of a "special" > name for the overlying probe while requiring the "real" name for the > underlying probe:? we have that problem for probe names.? There, we solve > the problem by checking the pid_probetype_t.? So maybe that same approach > should be used here, for probe function. > > Let me know.? If you agree/prefer, I can revise the patch. > > > > > > > ????? pid_t pps_pid;??????????????? /* task PID */ > > > > ????? uint64_t pps_nameoff;??????????? /* offset to use for name */ > > > > ? } pid_probespec_t; > > > > diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c > > > > @@ -182,8 +181,50 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const > > > > GElf_Sym *symp, const char *func) > > > > ????? psp->pps_fun = (char *) func; > > > > ????? psp->pps_nameoff = 0; > > > > ????? psp->pps_off = symp->st_value - pp->dpp_vaddr; > > > > +??? psp->pps_absoff = 0; > > > > ? -??? if (!isdash && gmatch("return", pp->dpp_name)) { > > > > +??? /* > > > > +???? * The special function "-" means the probe name is an absolute > > > > +???? * virtual address. > > > > +???? */ > > > > +??? if (strcmp("-", func) == 0) { > > > > +??????? char *end; > > > > +??????? GElf_Sym sym; > > > > + > > > > +??????? off = strtoull(pp->dpp_name, &end, 16); > > > > + > > > > +??????? psp->pps_absoff = 1; > > > > +??????? psp->pps_nameoff = off; > > > > + > > > > +??????? if (dt_Plookup_by_addr(dtp, pid, off, (const char > > > > **)&psp->pps_fun, &sym)) { > > > > +??????????? rc = dt_pid_error(dtp, pcb, dpr, D_PROC_NAME, > > > > +???????????????? "failed to lookup 0x%lx in module '%s'", off, > > > > pp->dpp_mod); > > > > +??????????? if (psp->pps_fun != func && psp->pps_fun != NULL) > > > > +??????????????? free(psp->pps_fun); > > > > +??????????? goto out; > > > > +??????? } > > > > + > > > > +??????? psp->pps_prb = (char*)pp->dpp_name;? // make sure > > > > dt_prov_uprobe uses it > > > > +??????? psp->pps_off = off - sym.st_value;?? // make sure > > > > dt_prov_uprobe uses it // dump this > > > > +??????? psp->pps_off = off - pp->dpp_vaddr;? // make sure > > > > dt_prov_uprobe uses it > > > > + > > > > +??????? if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, > > > > DTPPT_OFFSETS) < 0) > > > > +??????????? rc = dt_pid_error(dtp, pcb, dpr, D_PROC_CREATEFAIL, > > > > +??????????????? "failed to create probes at '%s+0x%llx': %s", > > > > +??????????????? func, (unsigned long long)off, > > > > dtrace_errmsg(dtp, dtrace_errno(dtp))); > > > > +??????? else > > > > +??????????? pp->dpp_nmatches++; > > > > +??????? free(psp->pps_fun); > > > > +??????? goto out; > > > > +??? } > > > > + > > > > +??? if (gmatch("return", pp->dpp_name)) { > > > > ????????? if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, > > > > DTPPT_RETURN) < 0) { > > > > ????????????? rc = dt_pid_error( > > > > ????????????????? dtp, pcb, dpr, D_PROC_CREATEFAIL, > > > > diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c > > > > index acf1c914f..ae4b262ac 100644 > > > > --- a/libdtrace/dt_prov_uprobe.c > > > > +++ b/libdtrace/dt_prov_uprobe.c > > > > @@ -735,7 +735,7 @@ static int provide_probe(dtrace_hdl_t *dtp, > > > > const pid_probespec_t *psp, > > > > ????? pd.id = DTRACE_IDNONE; > > > > ????? pd.prv = prv; > > > > ????? pd.mod = psp->pps_mod; > > > > -??? pd.fun = psp->pps_fun; > > > > +??? pd.fun = psp->pps_absoff ? "-" : psp->pps_fun; > > > > ????? pd.prb = prb; > > > > ? ????? /* Get (or create) the provider for the PID of the probe. */ From eugene.loh at oracle.com Fri Jan 10 06:30:50 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Fri, 10 Jan 2025 01:30:50 -0500 Subject: [DTrace-devel] [PATCH 6/6] Add support for pid function "-" with absolute offset In-Reply-To: References: <20241220222716.18511-1-eugene.loh@oracle.com> <20241220222716.18511-6-eugene.loh@oracle.com> <68af528d-8dbd-f081-835a-d92b42e3045e@oracle.com> <17bc480b-3785-7b7e-9df9-601d65038df8@oracle.com> Message-ID: <70efe39d-ec79-a959-f6fc-455fab4f0d51@oracle.com> On 1/10/25 00:07, Kris Van Hees wrote: > On Thu, Jan 09, 2025 at 04:00:42PM -0500, Eugene Loh wrote: >> On 1/9/25 15:52, Eugene Loh wrote: >>> On 1/9/25 14:12, Kris Van Hees wrote: >>>> On Fri, Dec 20, 2024 at 05:27:16PM -0500, eugene.loh--- via DTrace-devel wrote: >>>>> diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h >>>>> @@ -47,6 +47,7 @@ typedef struct pid_probespec { >>>>> ????? /* >>>>> ?????? * Fields below this point do not apply to underlying probes. >>>>> ?????? */ >>>>> +??? int pps_absoff;??????????????? /* use "-" for overlying probe function */ >>>> Why use this?? All you do with it is record that func is "-", and then later >>>> in the pid provider, you actually use that to force the function name in the >>>> probe description to be "-".? But that function name in the probe desc is (in >>>> the pid provider) already coming from pps_fun, and the code was already >>>> assigning func to pps_fun, so it would be "-" anyway.? So the pps_absoff seems >>>> to serve no purpose, and you could just rely on pps_fun being "-" when needed. >>> Yeah, good point.? Let me see if I can remember/understand/explain >>> what's going on here. >>> >>> In essence, the problem is we have to pass two function names: "-" (for >>> the overlying probe) and the actual function name (for the underlying >>> probe);? up until now, they were both the same.? I tossed around >>> different ideas for this.? E.g., pass two function names in. Or, get the >>> actual function name inside dt_prov_uprobe. It seemed to make most sense >>> (given the alternatives) to pass in the actual function name and add >>> this flag to say when the overlying probe's function name should be >>> "-".? Does that make sense? >>> >>> Note that pps_fun is not "-".? Although we set it to func ("-"), the >>> code that processes this case then fills pps_fun in with the actual >>> function name.? Again, one option is not to do this until >>> dt_prov_uprobe.c, but that introduces some other hassles. > Ok, I see what you mean... because we rely on underlying probes, we need to > track the function name that the absolute offset falls in in order to be able > to determine the underlying uprobe that the PID probe maps onto (especially > since there might be another probe on it already). > > However, as far as I can see there is not really any need to have a function > name on the underlying probe. After all, it is actually a uprobe that is > identified by dev/inode/offset where offset is an offset into the mapping at > dev/inode, i.e. not relative to any particular function at all. So, not > having the function name associated with the underlying probe would make more > sense than what we are doing now. > > And if we drop the function name from the underlying probe, we suddenly no > longer need to carry it across for absolute offset probe, and this entire > two-function name thing goes away. Right.? I considered that, but decided against it.? I think the reason was that, although we don't really need a function name for naming the underlying uprobe (as you point out), it's nice to have the function for the whole "USDT ignore clause" stuff.? Put another way, we *do* use the function name of the underlying probe... not so much for naming the uprobe but for an extra USDT ignore_clause() check.? If we wanted to, we could get rid of that check, but... well, that's the trade-off that we're facing here. >> Hmm.? Having said all that, maybe another (better?!) way of solving this >> problem is to add another probe type to pid_probetype_t.? Maybe >> DTPPT_ABSOFFSETS.? After all, we already have this problem of a "special" >> name for the overlying probe while requiring the "real" name for the >> underlying probe:? we have that problem for probe names.? There, we solve >> the problem by checking the pid_probetype_t.? So maybe that same approach >> should be used here, for probe function. >> >> Let me know.? If you agree/prefer, I can revise the patch. From kris.van.hees at oracle.com Fri Jan 10 14:47:26 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Fri, 10 Jan 2025 09:47:26 -0500 Subject: [DTrace-devel] [PATCH 6/6] Add support for pid function "-" with absolute offset In-Reply-To: <70efe39d-ec79-a959-f6fc-455fab4f0d51@oracle.com> References: <20241220222716.18511-1-eugene.loh@oracle.com> <20241220222716.18511-6-eugene.loh@oracle.com> <68af528d-8dbd-f081-835a-d92b42e3045e@oracle.com> <17bc480b-3785-7b7e-9df9-601d65038df8@oracle.com> <70efe39d-ec79-a959-f6fc-455fab4f0d51@oracle.com> Message-ID: On Fri, Jan 10, 2025 at 01:30:50AM -0500, Eugene Loh wrote: > On 1/10/25 00:07, Kris Van Hees wrote: > > > On Thu, Jan 09, 2025 at 04:00:42PM -0500, Eugene Loh wrote: > > > On 1/9/25 15:52, Eugene Loh wrote: > > > > On 1/9/25 14:12, Kris Van Hees wrote: > > > > > On Fri, Dec 20, 2024 at 05:27:16PM -0500, eugene.loh--- via DTrace-devel wrote: > > > > > > diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h > > > > > > @@ -47,6 +47,7 @@ typedef struct pid_probespec { > > > > > > ????? /* > > > > > > ?????? * Fields below this point do not apply to underlying probes. > > > > > > ?????? */ > > > > > > +??? int pps_absoff;??????????????? /* use "-" for overlying probe function */ > > > > > Why use this?? All you do with it is record that func is "-", and then later > > > > > in the pid provider, you actually use that to force the function name in the > > > > > probe description to be "-".? But that function name in the probe desc is (in > > > > > the pid provider) already coming from pps_fun, and the code was already > > > > > assigning func to pps_fun, so it would be "-" anyway.? So the pps_absoff seems > > > > > to serve no purpose, and you could just rely on pps_fun being "-" when needed. > > > > Yeah, good point.? Let me see if I can remember/understand/explain > > > > what's going on here. > > > > > > > > In essence, the problem is we have to pass two function names: "-" (for > > > > the overlying probe) and the actual function name (for the underlying > > > > probe);? up until now, they were both the same.? I tossed around > > > > different ideas for this.? E.g., pass two function names in. Or, get the > > > > actual function name inside dt_prov_uprobe. It seemed to make most sense > > > > (given the alternatives) to pass in the actual function name and add > > > > this flag to say when the overlying probe's function name should be > > > > "-".? Does that make sense? > > > > > > > > Note that pps_fun is not "-".? Although we set it to func ("-"), the > > > > code that processes this case then fills pps_fun in with the actual > > > > function name.? Again, one option is not to do this until > > > > dt_prov_uprobe.c, but that introduces some other hassles. > > Ok, I see what you mean... because we rely on underlying probes, we need to > > track the function name that the absolute offset falls in in order to be able > > to determine the underlying uprobe that the PID probe maps onto (especially > > since there might be another probe on it already). > > > > However, as far as I can see there is not really any need to have a function > > name on the underlying probe. After all, it is actually a uprobe that is > > identified by dev/inode/offset where offset is an offset into the mapping at > > dev/inode, i.e. not relative to any particular function at all. So, not > > having the function name associated with the underlying probe would make more > > sense than what we are doing now. > > > > And if we drop the function name from the underlying probe, we suddenly no > > longer need to carry it across for absolute offset probe, and this entire > > two-function name thing goes away. > > Right.? I considered that, but decided against it.? I think the reason was > that, although we don't really need a function name for naming the > underlying uprobe (as you point out), it's nice to have the function for the > whole "USDT ignore clause" stuff.? Put another way, we *do* use the function > name of the underlying probe... not so much for naming the uprobe but for an > extra USDT ignore_clause() check.? If we wanted to, we could get rid of that > check, but... well, that's the trade-off that we're facing here. II would propose that we do the following: - For absolute offset probes, use new type DTPPT_ABSOFF (or ABSOFFSET) as you suggest. The uprobe provider will use that to know that to put "-" as the function name component of the overlying probe. - For the underlying probe, store the function name (from pps_fun) in a member of dt_uprobe_t (fun or func, perhaps). That can be used in ignore_clause(). - For the underlying probe, leave the function name empty (to be consistent with the fact that the underlying probe is a uprobe, identified by dev/inode and offset within the inode.) This way we no longer display the function name for underlying probes in the probe listing, which is correct, and yet we retain the ignore_clause() optimization. Kris From eugene.loh at oracle.com Fri Jan 10 19:03:06 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Fri, 10 Jan 2025 14:03:06 -0500 Subject: [DTrace-devel] [PATCH] test: Have tst.ucaller use a predictable trigger Message-ID: <20250110190306.12814-1-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh --- test/unittest/vars/tst.ucaller.d | 16 ++++++++++++ test/unittest/vars/tst.ucaller.r | 2 +- test/unittest/vars/tst.ucaller.sh | 42 ------------------------------- test/unittest/vars/tst.ucaller.x | 1 - 4 files changed, 17 insertions(+), 44 deletions(-) create mode 100644 test/unittest/vars/tst.ucaller.d delete mode 100755 test/unittest/vars/tst.ucaller.sh delete mode 120000 test/unittest/vars/tst.ucaller.x diff --git a/test/unittest/vars/tst.ucaller.d b/test/unittest/vars/tst.ucaller.d new file mode 100644 index 000000000..271297fef --- /dev/null +++ b/test/unittest/vars/tst.ucaller.d @@ -0,0 +1,16 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* @@trigger: ustack-tst-basic */ + +#pragma D option quiet + +pid$target:a.out:myfunc_x:entry +{ + ufunc(ucaller); + exit(0); +} diff --git a/test/unittest/vars/tst.ucaller.r b/test/unittest/vars/tst.ucaller.r index 9b09daa0c..bfcc80f4d 100644 --- a/test/unittest/vars/tst.ucaller.r +++ b/test/unittest/vars/tst.ucaller.r @@ -1 +1 @@ - libc.so.6`strdup + ustack-tst-basic`myfunc_v diff --git a/test/unittest/vars/tst.ucaller.sh b/test/unittest/vars/tst.ucaller.sh deleted file mode 100755 index a6376af46..000000000 --- a/test/unittest/vars/tst.ucaller.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -# -# Oracle Linux DTrace. -# Copyright (c) 2007, 2020, 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 is a bit naughty; it's assuming that libc.so has an implementation -# of strup(3), and that it's implemented in terms of the libc.so -# implementation of malloc(3). If you're reading this comment because -# those assumptions have become false, please accept my apologies... -# -# @@xfail: dtv2 - -if [ $# != 1 ]; then - echo expected one argument: '<'dtrace-path'>' - exit 2 -fi - -dtrace=$1 - -$dtrace $dt_flags -qs /dev/stdin -c "/bin/wc -l /dev/zero" <strdup = 1; -} - -pid\$target:libc.so:malloc:entry -/self->strdup/ -{ - ufunc(ucaller); - exit(0); -} - -pid\$target::strdup:return -/self->strdup/ -{ - self->strdup = 0; -} -EOF - -exit 0 diff --git a/test/unittest/vars/tst.ucaller.x b/test/unittest/vars/tst.ucaller.x deleted file mode 120000 index 6507ccd87..000000000 --- a/test/unittest/vars/tst.ucaller.x +++ /dev/null @@ -1 +0,0 @@ -../pid/test.x \ No newline at end of file -- 2.43.5 From eugene.loh at oracle.com Tue Jan 14 23:37:50 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Tue, 14 Jan 2025 18:37:50 -0500 Subject: [DTrace-devel] [PATCH v2 6/6] Add support for pid function "-" with absolute offset Message-ID: <20250114233750.5425-1-eugene.loh@oracle.com> From: Eugene Loh The pid providers allow users to specify a probe function "-", meaning that the probe name gives an absolute offset. Signed-off-by: Eugene Loh --- include/dtrace/pid.h | 3 +- libdtrace/dt_pid.c | 79 +++++++++++++------ libdtrace/dt_prov_uprobe.c | 38 ++++++--- test/unittest/pid/tst.dash.r | 1 + test/unittest/pid/tst.dash.sh | 118 ++++++++++++++++++++++++++++ test/unittest/usdt/tst.pidprobes.sh | 21 ++++- 6 files changed, 223 insertions(+), 37 deletions(-) create mode 100644 test/unittest/pid/tst.dash.r create mode 100755 test/unittest/pid/tst.dash.sh diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h index c53e60047..12934500a 100644 --- a/include/dtrace/pid.h +++ b/include/dtrace/pid.h @@ -2,7 +2,7 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. * - * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. */ /* @@ -22,6 +22,7 @@ typedef enum pid_probetype { DTPPT_ENTRY, DTPPT_RETURN, DTPPT_OFFSETS, + DTPPT_ABSOFFSETS, DTPPT_USDT, DTPPT_IS_ENABLED } pid_probetype_t; diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index 11b964561..76608f690 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, 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. */ @@ -155,7 +155,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) uint_t nmatches = 0; ulong_t sz; int glob, rc = 0; - int isdash = strcmp("-", func) == 0; pid_t pid; /* @@ -183,7 +182,46 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) psp->pps_nameoff = 0; psp->pps_off = symp->st_value - pp->dpp_vaddr; - if (!isdash && gmatch("return", pp->dpp_name)) { + /* + * The special function "-" means the probe name is an absolute + * virtual address. + */ + if (strcmp("-", func) == 0) { + char *end; + GElf_Sym sym; + + off = strtoull(pp->dpp_name, &end, 16); + if (*end != '\0') { + rc = dt_pid_error(dtp, pcb, dpr, D_PROC_NAME, + "'%s' is an invalid probe name", + pp->dpp_name); + goto out; + } + + psp->pps_nameoff = off; + + if (dt_Plookup_by_addr(dtp, pid, off, (const char **)&psp->pps_fun, &sym)) { + rc = dt_pid_error(dtp, pcb, dpr, D_PROC_NAME, + "failed to lookup 0x%lx in module '%s'", off, pp->dpp_mod); + if (psp->pps_fun != func && psp->pps_fun != NULL) + free(psp->pps_fun); + goto out; + } + + psp->pps_prb = (char*)pp->dpp_name; + psp->pps_off = off - pp->dpp_vaddr; + + if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, DTPPT_ABSOFFSETS) < 0) + rc = dt_pid_error(dtp, pcb, dpr, D_PROC_CREATEFAIL, + "failed to create probes at '%s+0x%llx': %s", + func, (unsigned long long)off, dtrace_errmsg(dtp, dtrace_errno(dtp))); + else + pp->dpp_nmatches++; + free(psp->pps_fun); + goto out; + } + + if (gmatch("return", pp->dpp_name)) { if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, DTPPT_RETURN) < 0) { rc = dt_pid_error( dtp, pcb, dpr, D_PROC_CREATEFAIL, @@ -195,7 +233,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) nmatches++; } - if (!isdash && gmatch("entry", pp->dpp_name)) { + if (gmatch("entry", pp->dpp_name)) { if (dt_pid_create_one_probe(pp->dpp_pr, dtp, psp, DTPPT_ENTRY) < 0) { rc = dt_pid_error( dtp, pcb, dpr, D_PROC_CREATEFAIL, @@ -240,7 +278,7 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) } nmatches++; - } else if (glob && !isdash) { + } else if (glob) { #if defined(__amd64) /* * We need to step through the instructions to find their @@ -449,31 +487,25 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj) else pp->dpp_obj++; + /* + * If it is the special function "-", cut to dt_pid_per_sym() now. + */ + if (strcmp("-", pp->dpp_func) == 0) + return dt_pid_per_sym(pp, &sym, pp->dpp_func); + /* * If pp->dpp_func contains any globbing meta-characters, we need * to iterate over the symbol table and compare each function name * against the pattern. */ if (!strisglob(pp->dpp_func)) { - /* - * If we fail to lookup the symbol, try interpreting the - * function as the special "-" function that indicates that the - * probe name should be interpreted as a absolute virtual - * address. If that fails and we were matching a specific - * function in a specific module, report the error, otherwise - * just fail silently in the hopes that some other object will - * contain the desired symbol. + /* If we are matching a specific function in a specific module, + * report the error, otherwise just fail silently in the hopes + * that some other object will contain the desired symbol. */ if (dt_Pxlookup_by_name(dtp, pid, pp->dpp_lmid, obj, pp->dpp_func, &sym, NULL) != 0) { - if (strcmp("-", pp->dpp_func) == 0) { - sym.st_name = 0; - sym.st_info = - GELF_ST_INFO(STB_LOCAL, STT_FUNC); - sym.st_other = 0; - sym.st_value = 0; - sym.st_size = Pelf64(pp->dpp_pr) ? -1ULL : -1U; - } else if (!strisglob(pp->dpp_mod)) { + if (!strisglob(pp->dpp_mod)) { return dt_pid_error( dtp, pcb, dpr, D_PROC_FUNC, "failed to lookup '%s' in module '%s'", @@ -647,9 +679,10 @@ dt_pid_create_pid_probes_proc(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, if (strcmp(pp.dpp_func, "-") == 0) { const prmap_t *aout, *pmp; - if (pdp->mod[0] == '\0') { - pp.dpp_mod = pdp->mod; + if (strcmp(pp.dpp_mod, "*") == 0) { + /* Tolerate two glob cases: "" and "*". */ pdp->mod = "a.out"; + pp.dpp_mod = pdp->mod; } else if (strisglob(pp.dpp_mod) || (aout = dt_Pname_to_map(dtp, pid, "a.out")) == NULL || (pmp = dt_Pname_to_map(dtp, pid, pp.dpp_mod)) == NULL || diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index 11d595898..e96479963 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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. * @@ -55,7 +55,8 @@ static const char prvname[] = "uprobe"; typedef struct dt_uprobe { dev_t dev; ino_t inum; - char *fn; + char *fn; /* object full file name */ + char *func; /* function */ uint64_t off; int flags; tp_probe_t *tp; @@ -128,6 +129,7 @@ static void probe_destroy_underlying(dtrace_hdl_t *dtp, void *datap) dt_tp_destroy(dtp, tpp); free_probe_list(dtp, dt_list_next(&upp->probes)); dt_free(dtp, upp->fn); + dt_free(dtp, upp->func); dt_free(dtp, upp->args); dt_free(dtp, upp->argvbuf); dt_free(dtp, upp); @@ -333,9 +335,13 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *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; + if (strcmp(pdp->fun, "-") != 0) { + dt_uprobe_t *upp = uprp->prv_data; + + assert(upp->func); // never a return probe + if (!dt_gmatch(upp->func, pdp->fun)) + return 1; + } return 0; } @@ -623,11 +629,11 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, * * The probe description for non-return probes is: * - * uprobe:_:: + * uprobe:_:: * * The probe description for return probes is: * - * uprobe:_::return + * uprobe:_::return */ snprintf(mod, sizeof(mod), "%lx_%lx", psp->pps_dev, psp->pps_inum); @@ -638,6 +644,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, case DTPPT_IS_ENABLED: case DTPPT_ENTRY: case DTPPT_OFFSETS: + case DTPPT_ABSOFFSETS: case DTPPT_USDT: snprintf(prb, sizeof(prb), "%lx", psp->pps_off); break; @@ -649,7 +656,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, pd.id = DTRACE_IDNONE; pd.prv = prvname; pd.mod = mod; - pd.fun = psp->pps_fun; + pd.fun = ""; pd.prb = prb; dt_dprintf("Providing underlying probe %s:%s:%s:%s @ %lx\n", psp->pps_prv, @@ -672,6 +679,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, upp->inum = psp->pps_inum; upp->off = psp->pps_off; upp->fn = strdup(psp->pps_fn); + upp->func = NULL; upp->tp = dt_tp_alloc(dtp); if (upp->tp == NULL) goto fail; @@ -692,6 +700,17 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, goto fail; } + /* + * The underlying probe should have the same function for all + * overlying probes unless it's a return probe. + */ + if (psp->pps_type != DTPPT_RETURN) { + if (upp->func == NULL) + upp->func = strdup(psp->pps_fun); + else + assert(strcmp(upp->func, psp->pps_fun) == 0); + } + if (populate_args(dtp, psp, upp) < 0) goto fail; @@ -735,7 +754,7 @@ static int provide_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp, pd.id = DTRACE_IDNONE; pd.prv = prv; pd.mod = psp->pps_mod; - pd.fun = psp->pps_fun; + pd.fun = (psp->pps_type == DTPPT_ABSOFFSETS) ? "-" : psp->pps_fun; pd.prb = prb; /* Get (or create) the provider for the PID of the probe. */ @@ -823,6 +842,7 @@ static int provide_pid_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp) strcpy(prb, "return"); break; case DTPPT_OFFSETS: + case DTPPT_ABSOFFSETS: snprintf(prb, sizeof(prb), "%lx", psp->pps_nameoff); break; default: diff --git a/test/unittest/pid/tst.dash.r b/test/unittest/pid/tst.dash.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/pid/tst.dash.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/pid/tst.dash.sh b/test/unittest/pid/tst.dash.sh new file mode 100755 index 000000000..375a64536 --- /dev/null +++ b/test/unittest/pid/tst.dash.sh @@ -0,0 +1,118 @@ +#!/bin/bash +# +# Oracle Linux DTrace. +# Copyright (c) 2025, 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 + +DIRNAME=$tmpdir/pid-dash.$$.$RANDOM +mkdir $DIRNAME +cd $DIRNAME + +# Make trigger program. + +cat << EOF > main.c +int foo0(int i) { + int j, k; + + j = i ^ 1; k = j ^ 1; i = k ^ 1; + j = i ^ 1; k = j ^ 1; i = k ^ 1; + j = i ^ 1; k = j ^ 1; i = k ^ 1; + + return i; +} +int foo1(int i) { + int j, k; + + j = i ^ 1; k = j ^ 1; i = k ^ 1; + j = i ^ 1; k = j ^ 1; i = k ^ 1; + j = i ^ 1; k = j ^ 1; i = k ^ 1; + + return i; +} +int foo2(int i) { + int j, k; + + j = i ^ 1; k = j ^ 1; i = k ^ 1; + j = i ^ 1; k = j ^ 1; i = k ^ 1; + j = i ^ 1; k = j ^ 1; i = k ^ 1; + + return i; +} +int main(int c, char **v) { + int i = 0; + + i = foo0(i) ^ i; + i = foo1(i) ^ i; + i = foo2(i) ^ i; + + return i; +} +EOF + +gcc main.c +if [ $? -ne 0 ]; then + echo ERROR compile + exit 1 +fi + +# Loop over functions in the program. + +for func in foo0 foo1 foo2 main; do + # For each function, get the absolute and relative + # (to the function) address of some instruction in + # the function. + read ABS REL <<< `objdump -d a.out | awk ' + # Look for the function. + /^[0-9a-f]* <'$func'>:$/ { + + # Get the first instruction and note the base address of the function. + getline; sub(":", ""); base = strtonum("0x"$1); + + # Get the next instruction. + getline; + + # Get the next instruction. Note its PC. + getline; sub(":", ""); pc = strtonum("0x"$1); + + # Print the address, both absolute and relative. + printf("%x %x\n", pc, pc - base); + exit(0); + }'` + + # Write the expected output to the compare file. + echo got $ABS $func:$REL >> dtrace.exp + echo got $ABS "-":$ABS >> dtrace.exp + + # Write the actual dtrace output to the output file. + # Specify the pid probe with both relative and absolute + # forms. + for probe in $func:$REL "-:$ABS"; do + $dtrace -c ./a.out -o dtrace.out -qn ' + pid$target:a.out:'$probe' + { printf("got %x %s:%s", uregs[R_PC], probefunc, + probename); }' + if [ $? -ne 0 ]; then + echo ERROR: dtrace + cat dtrace.out + exit 1 + fi + done +done + +# Check results. + +if ! diff -q dtrace.exp dtrace.out; then + echo ERROR: + echo "==== expected" + cat dtrace.exp + echo "==== actual" + cat dtrace.out + exit 1 +fi + +echo success +exit 0 diff --git a/test/unittest/usdt/tst.pidprobes.sh b/test/unittest/usdt/tst.pidprobes.sh index 54444d49b..0c75d7967 100755 --- a/test/unittest/usdt/tst.pidprobes.sh +++ b/test/unittest/usdt/tst.pidprobes.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2024, 2025, 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. # @@ -121,7 +121,13 @@ fi pcs=`awk '{print strtonum("0x"$1)}' disasm_foo.txt` pc0=`echo $pcs | awk '{print $1}'` -# Run dtrace. +# Construct D script: add a pid$pid::-:$absoff probe for each PC in foo. + +for pc in $pcs; do + printf 'p*d$target::-:%x,\n' $pc >> pidprobes.d +done + +# Construct D script: add a glob for all pid and USDT pyramid probes in foo. cat >> pidprobes.d <<'EOF' p*d$target::foo: @@ -130,6 +136,8 @@ p*d$target::foo: } EOF +# Construct D script: add a glob for all USDT pyramid probes, dumping args. + if [[ -n $usdt ]]; then echo 'pyramid$target::foo: {' >> pidprobes.d @@ -141,9 +149,12 @@ if [[ -n $usdt ]]; then echo '}' >> pidprobes.d fi +# Run dtrace. + $dtrace $dt_flags -q -c ./main -o dtrace.out -s pidprobes.d > main.out2 if [ $? -ne 0 ]; then echo "failed to run dtrace" >&2 + cat pidprobes.d cat main.out2 cat dtrace.out exit 1 @@ -286,14 +297,16 @@ fi # - a blank line # - pid entry # - pid return -# - pid offset +# - pid offset (relative -- that is, pid$pid:main:foo:$reloff) +# - pid offset (absolute -- that is, pid$pid:main:-:$absoff) # - two USDT probes (ignore is-enabled probes) echo > dtrace.out.expected -printf "$pid pid$pid:main:foo:entry %x\n" $pc0 >> 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 + printf "$pid pid$pid:main:-:%x %x\n" $pc $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", $2);}' >> dtrace.out.expected -- 2.43.5 From eugene.loh at oracle.com Tue Jan 14 23:38:20 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Tue, 14 Jan 2025 18:38:20 -0500 Subject: [DTrace-devel] [PATCH] Convert some indenting spaces into tabs Message-ID: <20250114233820.5501-1-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh --- libdtrace/dt_prov_uprobe.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index e96479963..5d9f74244 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -593,7 +593,7 @@ static int populate_args(dtrace_hdl_t *dtp, const pid_probespec_t *psp, upp->args[i].mapping = map_arg; upp->args[i].flags = 0; - if (i != map_arg) + if (i != map_arg) upp->flags |= PP_IS_MAPPED; } @@ -716,21 +716,21 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, switch (psp->pps_type) { case DTPPT_RETURN: - upp->flags |= PP_IS_RETURN; - break; + upp->flags |= PP_IS_RETURN; + break; case DTPPT_IS_ENABLED: - upp->flags |= PP_IS_ENABLED; - break; + upp->flags |= PP_IS_ENABLED; + break; case DTPPT_USDT: - upp->flags |= PP_IS_USDT; - break; + upp->flags |= PP_IS_USDT; + break; default: ; - /* - * No flags needed for other types. - */ + /* + * No flags needed for other types. + */ } - return uprp; + return uprp; fail: dt_dprintf("Failed to instantiate %s:%s:%s:%s\n", psp->pps_prv, -- 2.43.5 From nick.alcock at oracle.com Thu Jan 16 21:33:31 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Thu, 16 Jan 2025 21:33:31 +0000 Subject: [DTrace-devel] [PATCH 1/2] dtprobed: handle a crashed parser child better Message-ID: <20250116213332.415905-1-nick.alcock@oracle.com> When a parser child crashes and is restarted, its file handles might change: we should pick up the new fhes if so. Signed-off-by: Nick Alcock --- dtprobed/dtprobed.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dtprobed/dtprobed.c b/dtprobed/dtprobed.c index 86865eb467b67..c0597b7329d37 100644 --- a/dtprobed/dtprobed.c +++ b/dtprobed/dtprobed.c @@ -769,7 +769,13 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, if (!provider) { if (tries++ > 1) goto err; + /* + * Tidying reopens the parser in and out pipes: catch + * up with this. + */ dof_parser_tidy(1); + out = parser_out_pipe; + in = parser_in_pipe; continue; } if (provider->type != DIT_PROVIDER && provider->type != DIT_EOF) -- 2.47.1.279.g84c5f4e78e From nick.alcock at oracle.com Thu Jan 16 21:33:32 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Thu, 16 Jan 2025 21:33:32 +0000 Subject: [DTrace-devel] [PATCH 2/2] libcommon: turn off FORTIFY_SOURCE more aggressively In-Reply-To: <20250116213332.415905-1-nick.alcock@oracle.com> References: <20250116213332.415905-1-nick.alcock@oracle.com> Message-ID: <20250116213332.415905-2-nick.alcock@oracle.com> This is incompatible with dof_parser_t's use of trailing strings of variable length, and buys us nothing anyway since we're running in a seccomped parser child and any buffer overruns are harmless and cannot result in anything other than a dying child. We were already -U'ing FORTIFY_SOURCE in libcommon_CPPFLAGS, but that precedes CFLAGS on the command line, so if the build system passes -D_FORTIFY_SOURCE there, it still takes effect. Use _NOCFLAGS and _NOCPPFLAGS to explicitly disable every level of fortification that currently exists. Signed-off-by: Nick Alcock --- libcommon/Build | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcommon/Build b/libcommon/Build index fd54dc044f9af..00c0d46d125e4 100644 --- a/libcommon/Build +++ b/libcommon/Build @@ -10,4 +10,6 @@ libcommon_TARGET = libcommon libcommon_DIR := $(current-dir) libcommon_CPPFLAGS := -Ilibcommon -Ilibproc -U_FORTIFY_SOURCE libcommon_SOURCES = dof_parser.c dof_parser_host.c dt_list.c +libcommon_NOCFLAGS := -D_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -D_FORTIFY_SOURCE=2 -D_FORTIFY_SOURCE=3 +libcommon_NOCPPFLAGS := -D_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -D_FORTIFY_SOURCE=2 -D_FORTIFY_SOURCE=3 libcommon_LIBSOURCES = libcommon -- 2.47.1.279.g84c5f4e78e From nick.alcock at oracle.com Thu Jan 16 21:54:17 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Thu, 16 Jan 2025 21:54:17 +0000 Subject: [DTrace-devel] [PATCH 1/2] tests: do not pass -flto to the compiler or linker Message-ID: <20250116215418.417155-1-nick.alcock@oracle.com> We don't want to compile tests with -flto by default: if the distro compiler automatically activates it, turn it off by explicitly passing -fno-lto to all compiler and linker invocations in the testsuite. (This is a bit fiddly because this is the first CPPFLAG which is not also a valid flag to dtrace(1) itself, so we have to split a variable up a bit.) Signed-off-by: Nick Alcock --- runtest.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/runtest.sh b/runtest.sh index 94634f80c2ebf..1cb5be8213396 100755 --- a/runtest.sh +++ b/runtest.sh @@ -589,8 +589,9 @@ else exit 1 fi fi -export test_cppflags -export test_ldflags +core_raw_dt_flags="$test_cppflags" +export test_cppflags="$test_cppflags -fno-lto" +export test_ldflags="$test_ldflags -fno-lto" export test_libdir # Figure out if the preprocessor supports -fno-diagnostics-show-option: if it @@ -1085,7 +1086,7 @@ for dt in $dtrace; do # Default and substitute in flags. The raw_dt_flags apply even to a # sh invocation. - raw_dt_flags="$test_cppflags" + raw_dt_flags="$core_raw_dt_flags" expected_tag= if [[ $testonly =~ ^err\.D_ ]]; then -- 2.47.1.279.g84c5f4e78e From nick.alcock at oracle.com Thu Jan 16 21:54:18 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Thu, 16 Jan 2025 21:54:18 +0000 Subject: [DTrace-devel] [PATCH 2/2] drti: do not compile with LTO In-Reply-To: <20250116215418.417155-1-nick.alcock@oracle.com> References: <20250116215418.417155-1-nick.alcock@oracle.com> Message-ID: <20250116215418.417155-2-nick.alcock@oracle.com> drti.o is shipped as object code and can be reused by many compiler versions: we must not put LTO IR into it. Signed-off-by: Nick Alcock --- libdtrace/Build | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libdtrace/Build b/libdtrace/Build index 722351591aaea..307d7e8bf6434 100644 --- a/libdtrace/Build +++ b/libdtrace/Build @@ -122,6 +122,10 @@ dt_prov_uprobe.c_CFLAGS := -Wno-pedantic dt_debug.c_CFLAGS := -Wno-prio-ctor-dtor drti.c_CFLAGS := -Wno-prio-ctor-dtor +# drti is shipped as an object file, so do not ever generate +# LTO for it, since that is compiler-version-specific. +drti.c_CFLAGS += -fno-lto + SHORTKERNELS := $(foreach kernel,$(KERNELS),$(shell printf %s $(kernel) | sed -e 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*$$/\1.\2.\3/')) -include libdtrace/$(ARCHINC)/Build -- 2.47.1.279.g84c5f4e78e From eugene.loh at oracle.com Thu Jan 16 22:04:15 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Thu, 16 Jan 2025 17:04:15 -0500 Subject: [DTrace-devel] [PATCH] Fix trampoline use of BPF stack for scratch Message-ID: <20250116220415.31864-1-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh --- libdtrace/dt_prov_proc.c | 14 +++++++------- test/unittest/lquantize/tst.32bit-bug26268136.sh | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libdtrace/dt_prov_proc.c b/libdtrace/dt_prov_proc.c index 0223c5d18..58e8ad147 100644 --- a/libdtrace/dt_prov_proc.c +++ b/libdtrace/dt_prov_proc.c @@ -62,7 +62,7 @@ static const char modname[] = "vmlinux"; * The dependent probe support should include a priority specification to drive * the order in which dependent probes are added to the underlying probe. This * is needed to enforce specific probe firing semantics (e.g. proc:::start must - * always precede [roc:::lwp-start). + * always precede [proc:::lwp-start). */ typedef struct probe_arg { @@ -350,12 +350,12 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) * else args[0] = 2; // CLD_KILLED */ emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_STK_SPILL(0))); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_MOV_IMM(BPF_REG_2, sizeof(int))); emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(0))); emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, ctm.ctm_offset / NBBY)); emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read)); - emit(dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_FP, DT_STK_SPILL(0))); + emit(dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_MOV_IMM(BPF_REG_0, 1)); emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_1)); emit(dlp, BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 0x7f)); @@ -406,17 +406,17 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, off)); emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_STK_SPILL(0))); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_MOV_IMM(BPF_REG_2, sz)); emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read)); - emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_FP, DT_STK_SPILL(0))); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); off = dt_cg_ctf_offsetof("struct signal_struct", "group_exit_code", &sz, 0); emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, off)); emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_STK_SPILL(0))); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_MOV_IMM(BPF_REG_2, sz)); emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read)); - emit(dlp, BPF_LOAD(BPF_W, BPF_REG_0, BPF_REG_FP, DT_STK_SPILL(0))); + emit(dlp, BPF_LOAD(BPF_W, BPF_REG_0, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_keep)); emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_0)); diff --git a/test/unittest/lquantize/tst.32bit-bug26268136.sh b/test/unittest/lquantize/tst.32bit-bug26268136.sh index d5f143f58..a360fd17e 100755 --- a/test/unittest/lquantize/tst.32bit-bug26268136.sh +++ b/test/unittest/lquantize/tst.32bit-bug26268136.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 if [ $# != 1 ]; then echo expected one argument: '<'dtrace-path'>' -- 2.43.5 From kris.van.hees at oracle.com Thu Jan 16 22:08:17 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 16 Jan 2025 17:08:17 -0500 Subject: [DTrace-devel] [PATCH 1/2] dtprobed: handle a crashed parser child better In-Reply-To: <20250116213332.415905-1-nick.alcock@oracle.com> References: <20250116213332.415905-1-nick.alcock@oracle.com> Message-ID: On Thu, Jan 16, 2025 at 09:33:31PM +0000, Nick Alcock via DTrace-devel wrote: > When a parser child crashes and is restarted, its file handles > might change: we should pick up the new fhes if so. > > Signed-off-by: Nick Alcock Reviewed-by: Kris Van Hees > --- > dtprobed/dtprobed.c | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/dtprobed/dtprobed.c b/dtprobed/dtprobed.c > index 86865eb467b67..c0597b7329d37 100644 > --- a/dtprobed/dtprobed.c > +++ b/dtprobed/dtprobed.c > @@ -769,7 +769,13 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, > if (!provider) { > if (tries++ > 1) > goto err; > + /* > + * Tidying reopens the parser in and out pipes: catch > + * up with this. > + */ > dof_parser_tidy(1); > + out = parser_out_pipe; > + in = parser_in_pipe; > continue; > } > if (provider->type != DIT_PROVIDER && provider->type != DIT_EOF) > -- > 2.47.1.279.g84c5f4e78e > > > _______________________________________________ > DTrace-devel mailing list > DTrace-devel at oss.oracle.com > https://oss.oracle.com/mailman/listinfo/dtrace-devel From kris.van.hees at oracle.com Thu Jan 16 22:09:57 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 16 Jan 2025 17:09:57 -0500 Subject: [DTrace-devel] [PATCH 2/2] libcommon: turn off FORTIFY_SOURCE more aggressively In-Reply-To: <20250116213332.415905-2-nick.alcock@oracle.com> References: <20250116213332.415905-1-nick.alcock@oracle.com> <20250116213332.415905-2-nick.alcock@oracle.com> Message-ID: On Thu, Jan 16, 2025 at 09:33:32PM +0000, Nick Alcock wrote: > This is incompatible with dof_parser_t's use of trailing strings of > variable length, and buys us nothing anyway since we're running in a > seccomped parser child and any buffer overruns are harmless and cannot > result in anything other than a dying child. We were already -U'ing > FORTIFY_SOURCE in libcommon_CPPFLAGS, but that precedes CFLAGS on the > command line, so if the build system passes -D_FORTIFY_SOURCE there, it > still takes effect. > > Use _NOCFLAGS and _NOCPPFLAGS to explicitly disable every level of > fortification that currently exists. > > Signed-off-by: Nick Alcock Reviewed-by: Kris Van Hees > --- > libcommon/Build | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/libcommon/Build b/libcommon/Build > index fd54dc044f9af..00c0d46d125e4 100644 > --- a/libcommon/Build > +++ b/libcommon/Build > @@ -10,4 +10,6 @@ libcommon_TARGET = libcommon > libcommon_DIR := $(current-dir) > libcommon_CPPFLAGS := -Ilibcommon -Ilibproc -U_FORTIFY_SOURCE > libcommon_SOURCES = dof_parser.c dof_parser_host.c dt_list.c > +libcommon_NOCFLAGS := -D_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -D_FORTIFY_SOURCE=2 -D_FORTIFY_SOURCE=3 > +libcommon_NOCPPFLAGS := -D_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -D_FORTIFY_SOURCE=2 -D_FORTIFY_SOURCE=3 > libcommon_LIBSOURCES = libcommon > -- > 2.47.1.279.g84c5f4e78e > From kris.van.hees at oracle.com Thu Jan 16 22:22:34 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 16 Jan 2025 17:22:34 -0500 Subject: [DTrace-devel] [PATCH 1/2] tests: do not pass -flto to the compiler or linker In-Reply-To: <20250116215418.417155-1-nick.alcock@oracle.com> References: <20250116215418.417155-1-nick.alcock@oracle.com> Message-ID: On Thu, Jan 16, 2025 at 09:54:17PM +0000, Nick Alcock wrote: > We don't want to compile tests with -flto by default: if the distro > compiler automatically activates it, turn it off by explicitly passing > -fno-lto to all compiler and linker invocations in the testsuite. > > (This is a bit fiddly because this is the first CPPFLAG which is > not also a valid flag to dtrace(1) itself, so we have to split > a variable up a bit.) > > Signed-off-by: Nick Alcock Reviewed-by: Kris Van Hees > --- > runtest.sh | 7 ++++--- > 1 file changed, 4 insertions(+), 3 deletions(-) > > diff --git a/runtest.sh b/runtest.sh > index 94634f80c2ebf..1cb5be8213396 100755 > --- a/runtest.sh > +++ b/runtest.sh > @@ -589,8 +589,9 @@ else > exit 1 > fi > fi > -export test_cppflags > -export test_ldflags > +core_raw_dt_flags="$test_cppflags" > +export test_cppflags="$test_cppflags -fno-lto" > +export test_ldflags="$test_ldflags -fno-lto" > export test_libdir > > # Figure out if the preprocessor supports -fno-diagnostics-show-option: if it > @@ -1085,7 +1086,7 @@ for dt in $dtrace; do > # Default and substitute in flags. The raw_dt_flags apply even to a > # sh invocation. > > - raw_dt_flags="$test_cppflags" > + raw_dt_flags="$core_raw_dt_flags" > > expected_tag= > if [[ $testonly =~ ^err\.D_ ]]; then > -- > 2.47.1.279.g84c5f4e78e > From kris.van.hees at oracle.com Thu Jan 16 22:24:44 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 16 Jan 2025 17:24:44 -0500 Subject: [DTrace-devel] [PATCH 2/2] drti: do not compile with LTO In-Reply-To: <20250116215418.417155-2-nick.alcock@oracle.com> References: <20250116215418.417155-1-nick.alcock@oracle.com> <20250116215418.417155-2-nick.alcock@oracle.com> Message-ID: On Thu, Jan 16, 2025 at 09:54:18PM +0000, Nick Alcock wrote: > drti.o is shipped as object code and can be reused by many compiler > versions: we must not put LTO IR into it. > > Signed-off-by: Nick Alcock Reviewed-by: Kris Van Hees > --- > libdtrace/Build | 4 ++++ > 1 file changed, 4 insertions(+) > > diff --git a/libdtrace/Build b/libdtrace/Build > index 722351591aaea..307d7e8bf6434 100644 > --- a/libdtrace/Build > +++ b/libdtrace/Build > @@ -122,6 +122,10 @@ dt_prov_uprobe.c_CFLAGS := -Wno-pedantic > dt_debug.c_CFLAGS := -Wno-prio-ctor-dtor > drti.c_CFLAGS := -Wno-prio-ctor-dtor > > +# drti is shipped as an object file, so do not ever generate > +# LTO for it, since that is compiler-version-specific. > +drti.c_CFLAGS += -fno-lto > + > SHORTKERNELS := $(foreach kernel,$(KERNELS),$(shell printf %s $(kernel) | sed -e 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*$$/\1.\2.\3/')) > > -include libdtrace/$(ARCHINC)/Build > -- > 2.47.1.279.g84c5f4e78e > From kris.van.hees at oracle.com Thu Jan 16 22:34:08 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 16 Jan 2025 17:34:08 -0500 Subject: [DTrace-devel] [PATCH] Fix trampoline use of BPF stack for scratch In-Reply-To: <20250116220415.31864-1-eugene.loh@oracle.com> References: <20250116220415.31864-1-eugene.loh@oracle.com> Message-ID: This would benefit from some explanation on why this is needed :) On Thu, Jan 16, 2025 at 05:04:15PM -0500, eugene.loh at oracle.com wrote: > From: Eugene Loh > > Signed-off-by: Eugene Loh > --- > libdtrace/dt_prov_proc.c | 14 +++++++------- > test/unittest/lquantize/tst.32bit-bug26268136.sh | 1 - > 2 files changed, 7 insertions(+), 8 deletions(-) > > diff --git a/libdtrace/dt_prov_proc.c b/libdtrace/dt_prov_proc.c > index 0223c5d18..58e8ad147 100644 > --- a/libdtrace/dt_prov_proc.c > +++ b/libdtrace/dt_prov_proc.c > @@ -62,7 +62,7 @@ static const char modname[] = "vmlinux"; > * The dependent probe support should include a priority specification to drive > * the order in which dependent probes are added to the underlying probe. This > * is needed to enforce specific probe firing semantics (e.g. proc:::start must > - * always precede [roc:::lwp-start). > + * always precede [proc:::lwp-start). drop the [ > */ > > typedef struct probe_arg { > @@ -350,12 +350,12 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) > * else args[0] = 2; // CLD_KILLED > */ > emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); > - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_STK_SPILL(0))); > + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_SLOT(0))); > emit(dlp, BPF_MOV_IMM(BPF_REG_2, sizeof(int))); > emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(0))); > emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, ctm.ctm_offset / NBBY)); > emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read)); > - emit(dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_FP, DT_STK_SPILL(0))); > + emit(dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); > emit(dlp, BPF_MOV_IMM(BPF_REG_0, 1)); > emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_1)); > emit(dlp, BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 0x7f)); > @@ -406,17 +406,17 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) > emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); > emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, off)); > emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); > - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_STK_SPILL(0))); > + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_SLOT(0))); > emit(dlp, BPF_MOV_IMM(BPF_REG_2, sz)); > emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read)); > - emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_FP, DT_STK_SPILL(0))); > + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); > off = dt_cg_ctf_offsetof("struct signal_struct", "group_exit_code", &sz, 0); > emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, off)); > emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); > - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_STK_SPILL(0))); > + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_SLOT(0))); > emit(dlp, BPF_MOV_IMM(BPF_REG_2, sz)); > emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read)); > - emit(dlp, BPF_LOAD(BPF_W, BPF_REG_0, BPF_REG_FP, DT_STK_SPILL(0))); > + emit(dlp, BPF_LOAD(BPF_W, BPF_REG_0, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); > emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_keep)); > emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_0)); > > diff --git a/test/unittest/lquantize/tst.32bit-bug26268136.sh b/test/unittest/lquantize/tst.32bit-bug26268136.sh > index d5f143f58..a360fd17e 100755 > --- a/test/unittest/lquantize/tst.32bit-bug26268136.sh > +++ b/test/unittest/lquantize/tst.32bit-bug26268136.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 > > if [ $# != 1 ]; then > echo expected one argument: '<'dtrace-path'>' > -- > 2.43.5 > From eugene.loh at oracle.com Thu Jan 16 23:14:14 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Thu, 16 Jan 2025 18:14:14 -0500 Subject: [DTrace-devel] [PATCH v2] Fix trampoline use of BPF stack for scratch Message-ID: <20250116231414.32553-1-eugene.loh@oracle.com> From: Eugene Loh The trampoline starts by setting %r9 = %fp + -DCTX_SIZE -- that is, %r9 = %fp - 88. Then, it fills the BPF stack from %fp-88 to %fp with the various dctx-> pointers. Calls to clauses will reset %fp. The proc provider's trampoline was using the BPF stack for scratch space for the exit and signal-handle probes. Specifically, it used %fp + DT_STK_SPILL(0), which overwrites a dctx-> pointer. Switch to DT_TRAMP_SP_SLOT(0), which is intended for this purpose. Signed-off-by: Eugene Loh --- libdtrace/dt_prov_proc.c | 14 +++++++------- test/unittest/lquantize/tst.32bit-bug26268136.sh | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libdtrace/dt_prov_proc.c b/libdtrace/dt_prov_proc.c index 0223c5d18..9fc499aeb 100644 --- a/libdtrace/dt_prov_proc.c +++ b/libdtrace/dt_prov_proc.c @@ -62,7 +62,7 @@ static const char modname[] = "vmlinux"; * The dependent probe support should include a priority specification to drive * the order in which dependent probes are added to the underlying probe. This * is needed to enforce specific probe firing semantics (e.g. proc:::start must - * always precede [roc:::lwp-start). + * always precede proc:::lwp-start). */ typedef struct probe_arg { @@ -350,12 +350,12 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) * else args[0] = 2; // CLD_KILLED */ emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_STK_SPILL(0))); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_MOV_IMM(BPF_REG_2, sizeof(int))); emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_7, DMST_ARG(0))); emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, ctm.ctm_offset / NBBY)); emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read)); - emit(dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_FP, DT_STK_SPILL(0))); + emit(dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_MOV_IMM(BPF_REG_0, 1)); emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_1)); emit(dlp, BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 0x7f)); @@ -406,17 +406,17 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, off)); emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_STK_SPILL(0))); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_MOV_IMM(BPF_REG_2, sz)); emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read)); - emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_FP, DT_STK_SPILL(0))); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_3, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); off = dt_cg_ctf_offsetof("struct signal_struct", "group_exit_code", &sz, 0); emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, off)); emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_STK_SPILL(0))); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_MOV_IMM(BPF_REG_2, sz)); emit(dlp, BPF_CALL_HELPER(BPF_FUNC_probe_read)); - emit(dlp, BPF_LOAD(BPF_W, BPF_REG_0, BPF_REG_FP, DT_STK_SPILL(0))); + emit(dlp, BPF_LOAD(BPF_W, BPF_REG_0, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_keep)); emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_0)); diff --git a/test/unittest/lquantize/tst.32bit-bug26268136.sh b/test/unittest/lquantize/tst.32bit-bug26268136.sh index d5f143f58..a360fd17e 100755 --- a/test/unittest/lquantize/tst.32bit-bug26268136.sh +++ b/test/unittest/lquantize/tst.32bit-bug26268136.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 if [ $# != 1 ]; then echo expected one argument: '<'dtrace-path'>' -- 2.43.5 From noreply at github.com Fri Jan 17 06:28:42 2025 From: noreply at github.com (Nick Alcock) Date: Thu, 16 Jan 2025 22:28:42 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] 02f327: dtprobed: handle a crashed parser child better Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: 02f327408812a4caa04db0096894471f98e6834e https://github.com/oracle/dtrace-utils/commit/02f327408812a4caa04db0096894471f98e6834e Author: Nick Alcock Date: 2025-01-16 (Thu, 16 Jan 2025) Changed paths: M dtprobed/dtprobed.c Log Message: ----------- dtprobed: handle a crashed parser child better When a parser child crashes and is restarted, its file handles might change: we should pick up the new fhes if so. Signed-off-by: Nick Alcock Reviewed-by: Kris Van Hees Commit: 68f2dec61aff39a775a2d7bed9904151aeb3e49b https://github.com/oracle/dtrace-utils/commit/68f2dec61aff39a775a2d7bed9904151aeb3e49b Author: Nick Alcock Date: 2025-01-17 (Fri, 17 Jan 2025) Changed paths: M libcommon/Build Log Message: ----------- libcommon: turn off FORTIFY_SOURCE more aggressively This is incompatible with dof_parser_t's use of trailing strings of variable length, and buys us nothing anyway since we're running in a seccomped parser child and any buffer overruns are harmless and cannot result in anything other than a dying child. We were already -U'ing FORTIFY_SOURCE in libcommon_CPPFLAGS, but that precedes CFLAGS on the command line, so if the build system passes -D_FORTIFY_SOURCE there, it still takes effect. Use _NOCFLAGS and _NOCPPFLAGS to explicitly disable every level of fortification that currently exists. Signed-off-by: Nick Alcock Signed-off-by: Kris Van Hees Reviewed-by: Kris Van Hees Commit: bb8fa79cbeda978da3123b9d4ad3afa570018924 https://github.com/oracle/dtrace-utils/commit/bb8fa79cbeda978da3123b9d4ad3afa570018924 Author: Nick Alcock Date: 2025-01-17 (Fri, 17 Jan 2025) Changed paths: M runtest.sh Log Message: ----------- tests: do not pass -flto to the compiler or linker We don't want to compile tests with -flto by default: if the distro compiler automatically activates it, turn it off by explicitly passing -fno-lto to all compiler and linker invocations in the testsuite. (This is a bit fiddly because this is the first CPPFLAG which is not also a valid flag to dtrace(1) itself, so we have to split a variable up a bit.) Signed-off-by: Nick Alcock Reviewed-by: Kris Van Hees Commit: 0fd90283cc03c640de3695d5f276dd6289a022db https://github.com/oracle/dtrace-utils/commit/0fd90283cc03c640de3695d5f276dd6289a022db Author: Nick Alcock Date: 2025-01-17 (Fri, 17 Jan 2025) Changed paths: M libdtrace/Build Log Message: ----------- drti: do not compile with LTO drti.o is shipped as object code and can be reused by many compiler versions: we must not put LTO IR into it. Signed-off-by: Nick Alcock Signed-off-by: Kris Van Hees Reviewed-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/a0a24ebf2a41...0fd90283cc03 To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From noreply at github.com Fri Jan 17 06:28:41 2025 From: noreply at github.com (Kris Van Hees) Date: Thu, 16 Jan 2025 22:28:41 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] Message-ID: Branch: refs/tags/2.0.2-rc4 Home: https://github.com/oracle/dtrace-utils To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From nick.alcock at oracle.com Mon Jan 20 18:49:34 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Mon, 20 Jan 2025 18:49:34 +0000 Subject: [DTrace-devel] [PATCH] translators: fix io.d.in devinfo_t.dev_{statname, pathname} Message-ID: <20250120184934.36967-1-nick.alcock@oracle.com> A precedence problem caused us to never accurately determine that a partitionless device was partitionless, producing erroneous names like "loop00" for conventional loop devices, etc. Fixed thusly: translators above 5.12 need regenerating. Fixes test/unittest/io/tst.{local,wait}.sh. Signed-off-by: Nick Alcock --- libdtrace/io.d.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdtrace/io.d.in b/libdtrace/io.d.in index f44f53f092dce..e5d5c19930e96 100644 --- a/libdtrace/io.d.in +++ b/libdtrace/io.d.in @@ -69,7 +69,7 @@ inline int REQ_SYNC = REQ_SYNC_VAL; define_for_kernel([[__bi_rw]], [[(m4_kver(4,8,0), [[bi_opf]])]], [[bi_rw]]) define_for_kernel([[__disk]], [[(m4_kver(5,12,0), [[bi_bdev->bd_disk]]), (m4_kver(4,14,0), [[bi_disk]])]], [[bi_bdev->bd_disk]]) define_for_kernel([[__disk_chk]], [[(m4_kver(5,12,0), [[bi_bdev]]), (m4_kver(4,14,0), [[bi_disk]])]], [[bi_bdev]]) -define_for_kernel([[__bio_partno]], [[(m4_kver(6,10,0), [[bi_bdev->__bd_flags.counter & BD_PARTNO]]), (m4_kver(5,12,0), [[bi_bdev->bd_partno]]), (m4_kver(4,14,0), [[bi_partno]])]], [[bi_bdev->bd_part->partno]]) +define_for_kernel([[__bio_partno]], [[(m4_kver(6,10,0), [[(bi_bdev->__bd_flags.counter & BD_PARTNO)]]), (m4_kver(5,12,0), [[bi_bdev->bd_partno]]), (m4_kver(4,14,0), [[bi_partno]])]], [[bi_bdev->bd_part->partno]]) define_for_kernel([[__bio_part_dev]], [[(m4_kver(5,12,0), [[bi_bdev->bd_dev]]), (m4_kver(5,11,0), [[bi_disk->part_tbl->part[B->bi_partno]->bd_dev]]), (m4_kver(4,14,0), [[bi_disk->part_tbl->part[B->bi_partno]->__dev.devt]])]], [[bi_bdev->bd_part->__dev.devt]]) #pragma D binding "1.6.3" translator base-commit: 0fd90283cc03c640de3695d5f276dd6289a022db -- 2.47.1.279.g84c5f4e78e From nick.alcock at oracle.com Tue Jan 21 18:16:17 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Tue, 21 Jan 2025 18:16:17 +0000 Subject: [DTrace-devel] [PATCH v2] translators: fix io.d.in devinfo_t.dev_{statname, pathname} Message-ID: <20250121181617.342071-1-nick.alcock@oracle.com> A precedence problem caused us to never accurately determine that a partitionless device was partitionless, producing erroneous names like "loop00" for conventional loop devices, etc. Fixed thusly: translators above 5.12 need regenerating. Fixes test/unittest/io/tst.{local,wait}.sh. Signed-off-by: Nick Alcock --- libdtrace/io.d.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdtrace/io.d.in b/libdtrace/io.d.in index f44f53f092dce..09915dbceafa2 100644 --- a/libdtrace/io.d.in +++ b/libdtrace/io.d.in @@ -135,7 +135,7 @@ translator devinfo_t < struct bio *B > { getmajor(B->__bio_part_dev) % 255 ]->name); dev_statname = B->__disk_chk == NULL ? "nfs" : - B->__bio_partno == 0 ? stringof(B->__disk->disk_name) : + (B->__bio_partno) == 0 ? stringof(B->__disk->disk_name) : strjoin(stringof(B->__disk->disk_name), lltostr(B->__bio_partno)); dev_pathname = B->__disk_chk == NULL ? "" : ""; }; base-commit: 0fd90283cc03c640de3695d5f276dd6289a022db -- 2.47.1.279.g84c5f4e78e From noreply at github.com Wed Jan 22 02:39:45 2025 From: noreply at github.com (Nick Alcock) Date: Tue, 21 Jan 2025 18:39:45 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] 38bb46: translators: fix io.d.in devinfo_t.dev_{statname, p... Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: 38bb46d7a50de85e878978b6040dcae34638b403 https://github.com/oracle/dtrace-utils/commit/38bb46d7a50de85e878978b6040dcae34638b403 Author: Nick Alcock Date: 2025-01-21 (Tue, 21 Jan 2025) Changed paths: M libdtrace/io.d.in Log Message: ----------- translators: fix io.d.in devinfo_t.dev_{statname,pathname} A precedence problem caused us to never accurately determine that a partitionless device was partitionless, producing erroneous names like "loop00" for conventional loop devices, etc. Fixed thusly: only broken for 6.10 and above but all translators need regenerating. Fixes test/unittest/io/tst.{local,wait}.sh. Signed-off-by: Nick Alcock Reviewed-by: Kris Van Hees To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From noreply at github.com Wed Jan 22 05:34:34 2025 From: noreply at github.com (Kris Van Hees) Date: Tue, 21 Jan 2025 21:34:34 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] Message-ID: Branch: refs/tags/2.0.2-rc5 Home: https://github.com/oracle/dtrace-utils To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From noreply at github.com Wed Jan 22 05:34:34 2025 From: noreply at github.com (Kris Van Hees) Date: Tue, 21 Jan 2025 21:34:34 -0800 Subject: [DTrace-devel] [oracle/dtrace-utils] 95cdf1: translators: fix io.d.in devinfo_t.dev_{statname, p... Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: 95cdf12b1c11163d278205e1ae0d4a4a846ec7fe https://github.com/oracle/dtrace-utils/commit/95cdf12b1c11163d278205e1ae0d4a4a846ec7fe Author: Nick Alcock Date: 2025-01-21 (Tue, 21 Jan 2025) Changed paths: M libdtrace/io.d.in Log Message: ----------- translators: fix io.d.in devinfo_t.dev_{statname,pathname} A precedence problem caused us to never accurately determine that a partitionless device was partitionless, producing erroneous names like "loop00" for conventional loop devices, etc. Fixed thusly: only broken for 6.10 and above but all translators need regenerating. Fixes test/unittest/io/tst.{local,wait}.sh. Signed-off-by: Nick Alcock Signed-off-by: Kris Van Hees Reviewed-by: Kris Van Hees Commit: 94e53e27cbb4d29ec292707cfaf448ac6d72a924 https://github.com/oracle/dtrace-utils/commit/94e53e27cbb4d29ec292707cfaf448ac6d72a924 Author: Kris Van Hees Date: 2025-01-21 (Tue, 21 Jan 2025) Changed paths: M dlibs/aarch64/6.10/io.d M dlibs/x86_64/6.10/io.d Log Message: ----------- translators: fix operator precedence in io.d for 6.10 Signed-off-by: Kris Van Hees Reviewed-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/38bb46d7a50d...94e53e27cbb4 To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From kris.van.hees at oracle.com Fri Jan 24 03:48:05 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 23 Jan 2025 22:48:05 -0500 Subject: [DTrace-devel] [PATCH] bpf: separate bvar implementation into separate functions Message-ID: The handling of builtin variables was done with a single big function that therefore got linked into every single BPF program (twice if the builtin variable might raise a fault). Providing separate functions for most builtin variables reduces BPF program size significantly. This also reduces pressure on the BPF verifies. Signed-off-by: Kris Van Hees --- bpf/get_bvar.c | 412 +++++++++++++----------- include/dtrace/dif_defines.h | 1 + libdtrace/dt_cg.c | 39 ++- libdtrace/dt_dis.c | 57 +++- libdtrace/dt_open.c | 2 + test/demo/builtin/ipl.d | 2 + test/demo/builtin/vtimestamp.d | 2 + test/demo/io/iocpu.d | 2 + test/unittest/buffering/tst.cputime.sh | 1 + test/unittest/disasm/tst.ann-bvar.r | 69 ++-- test/unittest/disasm/tst.ann-bvar.sh | 9 +- test/unittest/disasm/tst.vartab-bvar.r | 2 - test/unittest/disasm/tst.vartab-bvar.sh | 7 +- 13 files changed, 360 insertions(+), 245 deletions(-) diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c index 1c0fa884..c760126d 100644 --- a/bpf/get_bvar.c +++ b/bpf/get_bvar.c @@ -19,18 +19,21 @@ # define noinline __attribute__((noinline)) #endif -extern struct bpf_map_def cpuinfo; -extern struct bpf_map_def probes; -extern struct bpf_map_def state; -extern struct bpf_map_def usdt_names; - -extern uint64_t PC; -extern uint64_t STBSZ; -extern uint64_t STKSIZ; -extern uint64_t BOOTTM; +extern struct bpf_map_def cpuinfo; +extern struct bpf_map_def probes; +extern struct bpf_map_def state; +extern struct bpf_map_def usdt_names; + +extern uint64_t BOOTTM; +extern uint64_t NPROBES; +extern uint64_t PC; +extern uint64_t STBSZ; +extern uint64_t STKSIZ; extern uint64_t STACK_OFF; -extern uint64_t STACK_SKIP; -extern uint64_t NPROBES; +extern uint64_t STACK_SKIP; +extern uint64_t TASK_COMM; +extern uint64_t TASK_REAL_PARENT; +extern uint64_t TASK_TGID; #define error(dctx, fault, illval) \ ({ \ @@ -38,198 +41,231 @@ extern uint64_t NPROBES; -1; \ }) -noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx) +noinline uint64_t dt_bvar_args(const dt_dctx_t *dctx, uint32_t idx) { dt_mstate_t *mst = dctx->mst; - switch (id) { - case DIF_VAR_CURTHREAD: - return bpf_get_current_task(); - case DIF_VAR_TIMESTAMP: - if (mst->tstamp == 0) - mst->tstamp = bpf_ktime_get_ns(); + if (idx >= sizeof(mst->argv) / sizeof(mst->argv[0])) + return error(dctx, DTRACEFLT_ILLOP, 0); - return mst->tstamp; - case DIF_VAR_EPID: { - return (((uint64_t)mst->prid) << 32) | mst->stid; - } - case DIF_VAR_ID: - return mst->prid; - case DIF_VAR_ARG0: case DIF_VAR_ARG1: case DIF_VAR_ARG2: - case DIF_VAR_ARG3: case DIF_VAR_ARG4: case DIF_VAR_ARG5: - case DIF_VAR_ARG6: case DIF_VAR_ARG7: case DIF_VAR_ARG8: - case DIF_VAR_ARG9: - return mst->argv[id - DIF_VAR_ARG0]; - case DIF_VAR_ARGS: - if (idx >= sizeof(mst->argv) / sizeof(mst->argv[0])) - return error(dctx, DTRACEFLT_ILLOP, 0); - - return mst->argv[idx]; - case DIF_VAR_STACKDEPTH: - case DIF_VAR_USTACKDEPTH: { - uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); - uint64_t flags; - char *buf = dctx->mem + (uint64_t)(&STACK_OFF); - uint64_t stacksize; - - if (id == DIF_VAR_USTACKDEPTH) - flags = BPF_F_USER_STACK; - else - flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK; - - stacksize = bpf_get_stack(dctx->ctx, buf, bufsiz, flags); - if (stacksize < 0) - return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); + return mst->argv[idx]; +} + +noinline uint64_t dt_bvar_caller(const dt_dctx_t *dctx) +{ + uint64_t buf[2] = { 0, }; + if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), + (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK) < 0) + return 0; + + return buf[1]; +} + +noinline uint64_t dt_bvar_curcpu(const dt_dctx_t *dctx) +{ + uint32_t key = 0; + void *val = bpf_map_lookup_elem(&cpuinfo, &key); + + if (val == NULL) { /* - * While linux/bpf.h does not describe the meaning of - * bpf_get_stack()'s return value outside of its sign, - * it is presumably the length of the copied stack. - * - * If stacksize==bufsiz, presumably the stack is larger than - * what we can retrieve. But it's also possible that the - * buffer was exactly large enough. So, leave it to the user - * to interpret the result. + * Typically, we would use 'return error(...);' but + * that confuses the verifier because it returns -1. + * So, instead, we explicitly return 0. */ - return stacksize / sizeof(uint64_t); - } - case DIF_VAR_CALLER: - case DIF_VAR_UCALLER: { - uint64_t flags; - uint64_t buf[2] = { 0, }; - - if (id == DIF_VAR_UCALLER) - flags = BPF_F_USER_STACK; - else - flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK; - - if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), flags) < 0) - return 0; - return buf[1]; + error(dctx, DTRACEFLT_ILLOP, 0); + return 0; } - case DIF_VAR_PROBEPROV: - case DIF_VAR_PROBEMOD: - case DIF_VAR_PROBEFUNC: - case DIF_VAR_PROBENAME: { - uint32_t key = mst->prid; - - if (key < ((uint64_t)&NPROBES)) { - dt_bpf_probe_t *pinfo; - uint64_t off; - - pinfo = bpf_map_lookup_elem(&probes, &key); - if (pinfo == NULL) - return (uint64_t)dctx->strtab; - - switch (id) { - case DIF_VAR_PROBEPROV: - off = pinfo->prv; - break; - case DIF_VAR_PROBEMOD: - off = pinfo->mod; - break; - case DIF_VAR_PROBEFUNC: - off = pinfo->fun; - break; - case DIF_VAR_PROBENAME: - off = pinfo->prb; - } - if (off > (uint64_t)&STBSZ) - return (uint64_t)dctx->strtab; - - return (uint64_t)(dctx->strtab + off); - } else { - char *s; - - s = bpf_map_lookup_elem(&usdt_names, &key); - if (s == NULL) - return (uint64_t)dctx->strtab; - - switch (id) { - case DIF_VAR_PROBENAME: - s += DTRACE_FUNCNAMELEN; - case DIF_VAR_PROBEFUNC: - s += DTRACE_MODNAMELEN; - case DIF_VAR_PROBEMOD: - s += DTRACE_PROVNAMELEN; - case DIF_VAR_PROBEPROV: - } - - return (uint64_t)s; - } - } - case DIF_VAR_PID: { - uint64_t val = bpf_get_current_pid_tgid(); - return val >> 32; - } - case DIF_VAR_TID: { - uint64_t val = bpf_get_current_pid_tgid(); + return (uint64_t)val; +} - return val & 0x00000000ffffffffUL; - } - case DIF_VAR_EXECNAME: { - uint64_t ptr; - extern uint64_t TASK_COMM; +noinline uint64_t dt_bvar_curthread(const dt_dctx_t *dctx) +{ + return bpf_get_current_task(); +} - /* &(current->comm) */ - ptr = bpf_get_current_task(); - if (ptr == 0) - return error(dctx, DTRACEFLT_BADADDR, ptr); +noinline uint64_t dt_bvar_epid(const dt_dctx_t *dctx) +{ + dt_mstate_t *mst = dctx->mst; - return (uint64_t)ptr + (uint64_t)&TASK_COMM; - } - case DIF_VAR_WALLTIMESTAMP: - return bpf_ktime_get_ns() + ((uint64_t)&BOOTTM); - case DIF_VAR_PPID: { - uint64_t ptr; - int32_t val = -1; - extern uint64_t TASK_REAL_PARENT; - extern uint64_t TASK_TGID; - - /* Chase pointers val = current->real_parent->tgid. */ - ptr = bpf_get_current_task(); - if (ptr == 0) - return error(dctx, DTRACEFLT_BADADDR, ptr); - if (bpf_probe_read((void *)&ptr, 8, - (const void *)(ptr + (uint64_t)&TASK_REAL_PARENT))) - return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_REAL_PARENT); - if (bpf_probe_read((void *)&val, 4, - (const void *)(ptr + (uint64_t)&TASK_TGID))) - return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_TGID); - - return (uint64_t)val; - } - case DIF_VAR_UID: { - uint64_t val = bpf_get_current_uid_gid(); + return (((uint64_t)mst->prid) << 32) | mst->stid; +} - return val & 0x00000000ffffffffUL; - } - case DIF_VAR_GID: { - uint64_t val = bpf_get_current_uid_gid(); +noinline uint64_t dt_bvar_errno(const dt_dctx_t *dctx) +{ + dt_mstate_t *mst = dctx->mst; - return val >> 32; - } - case DIF_VAR_ERRNO: - return mst->syscall_errno; - case DIF_VAR_CURCPU: { - uint32_t key = 0; - void *val = bpf_map_lookup_elem(&cpuinfo, &key); - - if (val == NULL) { - /* - * Typically, we would use 'return error(...);' but - * that confuses the verifier because it returns -1. - * So, instead, we explicitly return 0. - */ - error(dctx, DTRACEFLT_ILLOP, 0); - return 0; + return mst->syscall_errno; +} + +noinline uint64_t dt_bvar_execname(const dt_dctx_t *dctx) +{ + uint64_t ptr; + + /* &(current->comm) */ + ptr = bpf_get_current_task(); + if (ptr == 0) + return error(dctx, DTRACEFLT_BADADDR, ptr); + + return (uint64_t)ptr + (uint64_t)&TASK_COMM; +} + +noinline uint64_t dt_bvar_gid(const dt_dctx_t *dctx) +{ + return bpf_get_current_uid_gid() >> 32; +} + +noinline uint64_t dt_bvar_id(const dt_dctx_t *dctx) +{ + dt_mstate_t *mst = dctx->mst; + + return mst->prid; +} + +noinline uint64_t dt_bvar_pid(const dt_dctx_t *dctx) +{ + return bpf_get_current_pid_tgid() >> 32; +} + +noinline uint64_t dt_bvar_ppid(const dt_dctx_t *dctx) +{ + uint64_t ptr; + int32_t val = -1; + + /* Chase pointers val = current->real_parent->tgid. */ + ptr = bpf_get_current_task(); + if (ptr == 0) + return error(dctx, DTRACEFLT_BADADDR, ptr); + if (bpf_probe_read((void *)&ptr, 8, + (const void *)(ptr + (uint64_t)&TASK_REAL_PARENT))) + return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_REAL_PARENT); + if (bpf_probe_read((void *)&val, 4, + (const void *)(ptr + (uint64_t)&TASK_TGID))) + return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_TGID); + + return (uint64_t)val; +} + +noinline uint64_t dt_bvar_probedesc(const dt_dctx_t *dctx, uint32_t idx) +{ + dt_mstate_t *mst = dctx->mst; + uint32_t key = mst->prid; + + if (key < ((uint64_t)&NPROBES)) { + dt_bpf_probe_t *pinfo; + uint64_t off = 0; + + pinfo = bpf_map_lookup_elem(&probes, &key); + if (pinfo == NULL) + return (uint64_t)dctx->strtab; + + switch (idx) { + case DIF_VAR_PROBEPROV: + off = pinfo->prv; + break; + case DIF_VAR_PROBEMOD: + off = pinfo->mod; + break; + case DIF_VAR_PROBEFUNC: + off = pinfo->fun; + break; + case DIF_VAR_PROBENAME: + off = pinfo->prb; } + if (off > (uint64_t)&STBSZ) + return (uint64_t)dctx->strtab; - return (uint64_t)val; - } - default: - /* Not implemented yet. */ - return error(dctx, DTRACEFLT_ILLOP, 0); + return (uint64_t)(dctx->strtab + off); + } else { + char *s; + + s = bpf_map_lookup_elem(&usdt_names, &key); + if (s == NULL) + return (uint64_t)dctx->strtab; + + switch (idx) { + case DIF_VAR_PROBEPROV: + s += DTRACE_FUNCNAMELEN; + case DIF_VAR_PROBEMOD: + s += DTRACE_MODNAMELEN; + case DIF_VAR_PROBEFUNC: + s += DTRACE_PROVNAMELEN; + case DIF_VAR_PROBENAME: + } + + return (uint64_t)s; } } + +noinline uint64_t dt_bvar_stackdepth(const dt_dctx_t *dctx) +{ + uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); + char *buf = dctx->mem + (uint64_t)(&STACK_OFF); + uint64_t retv; + + retv = bpf_get_stack(dctx->ctx, buf, bufsiz, + (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK); + if (retv < 0) + return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); + + /* + * While linux/bpf.h does not describe the meaning of bpf_get_stack()'s + * return value outside of its sign, it is presumably the length of the + * copied stack. + * + * If retv==bufsiz, presumably the stack is larger than what we + * can retrieve. But it's also possible that the buffer was exactly + * large enough. So, leave it to the user to interpret the result. + */ + return retv / sizeof(uint64_t); +} + +noinline uint64_t dt_bvar_tid(const dt_dctx_t *dctx) +{ + return bpf_get_current_pid_tgid() & 0x00000000ffffffffUL; +} + +noinline uint64_t dt_bvar_timestamp(const dt_dctx_t *dctx) +{ + dt_mstate_t *mst = dctx->mst; + + if (mst->tstamp == 0) + mst->tstamp = bpf_ktime_get_ns(); + + return mst->tstamp; +} + +noinline uint64_t dt_bvar_ucaller(const dt_dctx_t *dctx) +{ + uint64_t buf[2] = { 0, }; + + if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), BPF_F_USER_STACK) < 0) + return 0; + + return buf[1]; +} + +noinline uint64_t dt_bvar_uid(const dt_dctx_t *dctx) +{ + return bpf_get_current_uid_gid() & 0x00000000ffffffffUL; +} + +noinline uint64_t dt_bvar_ustackdepth(const dt_dctx_t *dctx) +{ + uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); + char *buf = dctx->mem + (uint64_t)(&STACK_OFF); + uint64_t retv; + + retv = bpf_get_stack(dctx->ctx, buf, bufsiz, BPF_F_USER_STACK); + if (retv < 0) + return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); + + /* See dt_bvar_stackdepth() above. */ + return retv / sizeof(uint64_t); +} + +noinline uint64_t dt_bvar_walltimestamp(const dt_dctx_t *dctx) +{ + return bpf_ktime_get_ns() + ((uint64_t)&BOOTTM); +} diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h index c8c1d961..9f6e3b55 100644 --- a/include/dtrace/dif_defines.h +++ b/include/dtrace/dif_defines.h @@ -162,6 +162,7 @@ #define DIF_VAR_GID 0x011f #define DIF_VAR_ERRNO 0x0120 #define DIF_VAR_CURCPU 0x0121 +#define DIF_VAR_EXECARGS 0x0122 #define DIF_SUBR_RAND 0 #define DIF_SUBR_MUTEX_OWNED 1 diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index e7e3a132..6e74b4b0 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -3197,6 +3197,7 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) { dt_ident_t *idp = dt_ident_resolve(dnp->dn_ident); dt_ident_t *fnp; + uint32_t idx = UINT32_MAX; idp->di_flags |= DT_IDFLG_DIFR; @@ -3298,15 +3299,38 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) return; } - /* built-in variables */ + /* built-in variables (note: args[] is handled in dt_cg_array_op) */ + /* Special case for arg0 through arg9; encode as args[n] */ + if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); + idx = idp->di_id - DIF_VAR_ARG0; + } else if (idp->di_id == DIF_VAR_PROBEPROV || + idp->di_id == DIF_VAR_PROBEMOD || + idp->di_id == DIF_VAR_PROBEFUNC || + idp->di_id == DIF_VAR_PROBENAME) { + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_probedesc"); + idx = idp->di_id; + } else { + char *fn; + + if (asprintf(&fn, "dt_bvar_%s", idp->di_name) == -1) + longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); + + fnp = dt_dlib_get_func(yypcb->pcb_hdl, fn); + free(fn); + } + + /* No implementing function found - report ILLOP. */ + if (fnp == NULL) + xyerror(D_IDENT_UNDEF, + "built-in variable '%s' not implemented", idp->di_name); + if (dt_regset_xalloc_args(drp) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1); - emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id)); - emit(dlp, BPF_MOV_IMM(BPF_REG_3, 0)); - fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar"); - assert(fnp != NULL); + if (idx != UINT32_MAX) + emit(dlp, BPF_MOV_IMM(BPF_REG_2, idx)); dt_regset_xalloc(drp, BPF_REG_0); emite(dlp, BPF_CALL_FUNC(fnp->di_id), fnp); dt_regset_free_args(drp); @@ -5065,7 +5089,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) dt_probe_t *prp = yypcb->pcb_probe; uintmax_t saved = dnp->dn_args->dn_value; dt_ident_t *idp = dnp->dn_ident; - dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar"); + dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); size_t size; int n; int ustr = 0; @@ -5135,8 +5159,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) if (dt_regset_xalloc_args(drp) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1); - emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id)); - emit(dlp, BPF_MOV_REG(BPF_REG_3, dnp->dn_reg)); + emit(dlp, BPF_MOV_REG(BPF_REG_2, dnp->dn_reg)); dt_regset_xalloc(drp, BPF_REG_0); emite(dlp, BPF_CALL_FUNC(fidp->di_id), fidp); dt_regset_free_args(drp); diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c index 9f319d70..d983c099 100644 --- a/libdtrace/dt_dis.c +++ b/libdtrace/dt_dis.c @@ -364,16 +364,57 @@ static char * dt_dis_bpf_args(const dtrace_difo_t *dp, const char *fn, const struct bpf_insn *in, char *buf, size_t len, uint_t addr) { - if (strcmp(fn, "dt_get_bvar") == 0) { + if (strcmp(fn, "dt_bvar_args") == 0) { /* - * We know that the previous two instructions exist and move - * the variable id to a register in the first instruction of - * that sequence (because we wrote the code generator to emit - * the instructions in this exact order.) + * We need to support two cases: + * - access to argN: + * lddw %r1, dctx + * mov %r2, N + * call dt_bvar_args + * - access to args[N]: + * mov %rX, N + * lddw %r1, dctx + * mov %r2, %rX + * call dt_bvar_args */ - in -= 2; - snprintf(buf, len, "%s", - dt_dis_varname_id(dp, in->imm, DIFV_SCOPE_GLOBAL, addr)); + in--; + if (BPF_OP(in->code) == BPF_MOV && in->dst_reg == 2) { + if (BPF_SRC(in->code) == BPF_K) { + snprintf(buf, len, "arg%d", in->imm); + return buf; + } + + in -= 2; + if (BPF_OP(in->code) == BPF_MOV && + BPF_SRC(in->code) == BPF_K && + in->dst_reg == in[2].src_reg) { + snprintf(buf, len, "args[%d]", in->imm); + return buf; + } + } + + snprintf(buf, len, "args[?]"); + return buf; + } else if (strcmp(fn, "dt_bvar_probedesc") == 0) { + /* + * Access to probe(prov|mod|func|name); + * lddw %r1, dctx + * mov %r2, N + * call dt_bvar_probedesc + */ + in--; + if (BPF_OP(in->code) == BPF_MOV && in->dst_reg == 2 && + BPF_SRC(in->code) == BPF_K) { + snprintf(buf, len, "%s", + dt_dis_varname_id(dp, in->imm, + DIFV_SCOPE_GLOBAL, addr)); + return buf; + } + + return NULL; + } else if (strncmp(fn, "dt_bvar_", 8) == 0) { + /* The variable name is in the function name.*/ + snprintf(buf, len, "%s", fn + 8); return buf; } else if (strcmp(fn, "dt_get_agg") == 0) { /* diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c index a0205887..51c056b2 100644 --- a/libdtrace/dt_open.c +++ b/libdtrace/dt_open.c @@ -153,6 +153,8 @@ static const dt_ident_t _dtrace_globals[] = { &dt_idops_type, "uint64_t" }, { "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int" }, +{ "execargs", DT_IDENT_SCALAR, 0, DIF_VAR_EXECARGS, + DT_ATTR_STABCMN, DT_VERS_2_0, &dt_idops_type, "string" }, { "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "exit", DT_IDENT_ACTFUNC, 0, DT_ACT_EXIT, DT_ATTR_STABCMN, DT_VERS_1_0, diff --git a/test/demo/builtin/ipl.d b/test/demo/builtin/ipl.d index ca7f3bb7..f613bb70 100644 --- a/test/demo/builtin/ipl.d +++ b/test/demo/builtin/ipl.d @@ -1,3 +1,5 @@ +/* @@xfail: dtv2: need ipl support */ + BEGIN { trace(ipl); exit(0); diff --git a/test/demo/builtin/vtimestamp.d b/test/demo/builtin/vtimestamp.d index 9f01bbf0..fcb708d0 100644 --- a/test/demo/builtin/vtimestamp.d +++ b/test/demo/builtin/vtimestamp.d @@ -1,3 +1,5 @@ +/* @@xfail: dtv2: need vtimestamp support */ + BEGIN { trace(vtimestamp); exit(0); diff --git a/test/demo/io/iocpu.d b/test/demo/io/iocpu.d index c7b847e7..1230d6f6 100644 --- a/test/demo/io/iocpu.d +++ b/test/demo/io/iocpu.d @@ -5,6 +5,8 @@ * http://oss.oracle.com/licenses/upl. */ +/* @@xfail: dtv2: need vtimestamp support */ + #pragma D option quiet sched:::on-cpu diff --git a/test/unittest/buffering/tst.cputime.sh b/test/unittest/buffering/tst.cputime.sh index 6a420e8d..c0e248a6 100755 --- a/test/unittest/buffering/tst.cputime.sh +++ b/test/unittest/buffering/tst.cputime.sh @@ -5,6 +5,7 @@ # Licensed under the Universal Permissive License v 1.0 as shown at # http://oss.oracle.com/licenses/upl. # +# @@xfail: dtv2: need vtimestamp support # @@timeout: 12 script() diff --git a/test/unittest/disasm/tst.ann-bvar.r b/test/unittest/disasm/tst.ann-bvar.r index b514dd99..a55fb6de 100644 --- a/test/unittest/disasm/tst.ann-bvar.r +++ b/test/unittest/disasm/tst.ann-bvar.r @@ -1,34 +1,35 @@ -85 0 1 0000 ffffffff call dt_get_bvar ! arg0 -85 0 1 0000 ffffffff call dt_get_bvar ! arg1 -85 0 1 0000 ffffffff call dt_get_bvar ! arg2 -85 0 1 0000 ffffffff call dt_get_bvar ! arg3 -85 0 1 0000 ffffffff call dt_get_bvar ! arg4 -85 0 1 0000 ffffffff call dt_get_bvar ! arg5 -85 0 1 0000 ffffffff call dt_get_bvar ! arg6 -85 0 1 0000 ffffffff call dt_get_bvar ! arg7 -85 0 1 0000 ffffffff call dt_get_bvar ! arg8 -85 0 1 0000 ffffffff call dt_get_bvar ! arg9 -85 0 1 0000 ffffffff call dt_get_bvar ! args -85 0 1 0000 ffffffff call dt_get_bvar ! caller -85 0 1 0000 ffffffff call dt_get_bvar ! curcpu -85 0 1 0000 ffffffff call dt_get_bvar ! curthread -85 0 1 0000 ffffffff call dt_get_bvar ! epid -85 0 1 0000 ffffffff call dt_get_bvar ! errno -85 0 1 0000 ffffffff call dt_get_bvar ! execname -85 0 1 0000 ffffffff call dt_get_bvar ! gid -85 0 1 0000 ffffffff call dt_get_bvar ! id -85 0 1 0000 ffffffff call dt_get_bvar ! ipl -85 0 1 0000 ffffffff call dt_get_bvar ! pid -85 0 1 0000 ffffffff call dt_get_bvar ! ppid -85 0 1 0000 ffffffff call dt_get_bvar ! probefunc -85 0 1 0000 ffffffff call dt_get_bvar ! probemod -85 0 1 0000 ffffffff call dt_get_bvar ! probename -85 0 1 0000 ffffffff call dt_get_bvar ! probeprov -85 0 1 0000 ffffffff call dt_get_bvar ! stackdepth -85 0 1 0000 ffffffff call dt_get_bvar ! tid -85 0 1 0000 ffffffff call dt_get_bvar ! timestamp -85 0 1 0000 ffffffff call dt_get_bvar ! ucaller -85 0 1 0000 ffffffff call dt_get_bvar ! uid -85 0 1 0000 ffffffff call dt_get_bvar ! ustackdepth -85 0 1 0000 ffffffff call dt_get_bvar ! vtimestamp -85 0 1 0000 ffffffff call dt_get_bvar ! walltimestamp +85 0 1 0000 ffffffff call dt_bvar_args ! arg0 +85 0 1 0000 ffffffff call dt_bvar_args ! arg1 +85 0 1 0000 ffffffff call dt_bvar_args ! arg2 +85 0 1 0000 ffffffff call dt_bvar_args ! arg3 +85 0 1 0000 ffffffff call dt_bvar_args ! arg4 +85 0 1 0000 ffffffff call dt_bvar_args ! arg5 +85 0 1 0000 ffffffff call dt_bvar_args ! arg6 +85 0 1 0000 ffffffff call dt_bvar_args ! arg7 +85 0 1 0000 ffffffff call dt_bvar_args ! arg8 +85 0 1 0000 ffffffff call dt_bvar_args ! arg9 +85 0 1 0000 ffffffff call dt_bvar_args ! args[0] +85 0 1 0000 ffffffff call dt_bvar_args ! args[1] +85 0 1 0000 ffffffff call dt_bvar_args ! args[2] +85 0 1 0000 ffffffff call dt_bvar_args ! args[3] +85 0 1 0000 ffffffff call dt_bvar_caller ! caller +85 0 1 0000 ffffffff call dt_bvar_curcpu ! curcpu +85 0 1 0000 ffffffff call dt_bvar_curthread ! curthread +85 0 1 0000 ffffffff call dt_bvar_epid ! epid +85 0 1 0000 ffffffff call dt_bvar_errno ! errno +85 0 1 0000 ffffffff call dt_bvar_execname ! execname +85 0 1 0000 ffffffff call dt_bvar_gid ! gid +85 0 1 0000 ffffffff call dt_bvar_id ! id +85 0 1 0000 ffffffff call dt_bvar_pid ! pid +85 0 1 0000 ffffffff call dt_bvar_ppid ! ppid +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probefunc +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probemod +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probename +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probeprov +85 0 1 0000 ffffffff call dt_bvar_stackdepth ! stackdepth +85 0 1 0000 ffffffff call dt_bvar_tid ! tid +85 0 1 0000 ffffffff call dt_bvar_timestamp ! timestamp +85 0 1 0000 ffffffff call dt_bvar_ucaller ! ucaller +85 0 1 0000 ffffffff call dt_bvar_uid ! uid +85 0 1 0000 ffffffff call dt_bvar_ustackdepth ! ustackdepth +85 0 1 0000 ffffffff call dt_bvar_walltimestamp ! walltimestamp diff --git a/test/unittest/disasm/tst.ann-bvar.sh b/test/unittest/disasm/tst.ann-bvar.sh index 6dc43424..61e838d1 100755 --- a/test/unittest/disasm/tst.ann-bvar.sh +++ b/test/unittest/disasm/tst.ann-bvar.sh @@ -22,6 +22,9 @@ sdt:task::task_rename trace(arg8); trace(arg9); trace(args[0]); + trace(args[1]); + trace(args[2]); + trace(args[3]); trace(caller); trace(curcpu); trace(curthread); @@ -30,7 +33,7 @@ sdt:task::task_rename trace(execname); trace(gid); trace(id); - trace(ipl); +/* trace(ipl); */ trace(pid); trace(ppid); trace(probefunc); @@ -43,10 +46,10 @@ sdt:task::task_rename trace(ucaller); trace(uid); trace(ustackdepth); - trace(vtimestamp); +/* trace(vtimestamp); */ trace(walltimestamp); exit(0); } -' 2>&1 | gawk '/ call dt_get_bvar/ { sub(/^[^:]+: /, ""); print; }' +' 2>&1 | gawk '/ call dt_bvar_/ { sub(/^[^:]+: /, ""); print; }' exit $? diff --git a/test/unittest/disasm/tst.vartab-bvar.r b/test/unittest/disasm/tst.vartab-bvar.r index 53e5f618..04fa3a8d 100644 --- a/test/unittest/disasm/tst.vartab-bvar.r +++ b/test/unittest/disasm/tst.vartab-bvar.r @@ -2,8 +2,6 @@ NAME OFFSET KND SCP FLAG TYPE args arr glb r any (unknown) by ref (size 0) 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 8) id scl glb r D type (integer) (size 4) arg0 scl glb r D type (integer) (size 8) diff --git a/test/unittest/disasm/tst.vartab-bvar.sh b/test/unittest/disasm/tst.vartab-bvar.sh index 098c1f45..ce489a24 100755 --- a/test/unittest/disasm/tst.vartab-bvar.sh +++ b/test/unittest/disasm/tst.vartab-bvar.sh @@ -30,6 +30,9 @@ sdt:task::task_rename trace(arg8); trace(arg9); trace(args[0]); + trace(args[1]); + trace(args[2]); + trace(args[3]); trace(caller); trace(curcpu); trace(curthread); @@ -38,7 +41,7 @@ sdt:task::task_rename trace(execname); trace(gid); trace(id); - trace(ipl); +/* trace(ipl); */ trace(pid); trace(ppid); trace(probefunc); @@ -52,7 +55,7 @@ sdt:task::task_rename trace(uid); /* trace(uregs[0]); */ /* test this separately until uregs[0] works on all kernels */ trace(ustackdepth); - trace(vtimestamp); +/* trace(vtimestamp); */ trace(walltimestamp); exit(0); } -- 2.45.2 From eugene.loh at oracle.com Fri Jan 24 07:35:49 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Fri, 24 Jan 2025 02:35:49 -0500 Subject: [DTrace-devel] [PATCH] bpf: separate bvar implementation into separate functions In-Reply-To: References: Message-ID: <252a8cc4-0bcc-a41c-997d-f5c264c1ed1c@oracle.com> I think I'm on board with this patch, but two questions. 1.? There is DIF_VAR_EXECARGS stuff in two places.? Is that stuff in the wrong patch? 2.? I'm confused why ? ?? ?? test/demo/builtin/ipl.d ??????? test/demo/builtin/vtimestamp.d were passing:? there was no ipl or vtimestamp support before and there is none now.? Presumably, the tests used to time out... so why was that considered a PASS?? I guess I see why test/unittest/buffering/tst.cputime.sh used to pass, but maybe that suggests that the test needs to be tightened up and be made quite a bit more discriminating. On 1/23/25 22:48, Kris Van Hees wrote: > The handling of builtin variables was done with a single big function > that therefore got linked into every single BPF program (twice if the > builtin variable might raise a fault). Providing separate functions > for most builtin variables reduces BPF program size significantly. > > This also reduces pressure on the BPF verifies. > > Signed-off-by: Kris Van Hees > --- > bpf/get_bvar.c | 412 +++++++++++++----------- > include/dtrace/dif_defines.h | 1 + > libdtrace/dt_cg.c | 39 ++- > libdtrace/dt_dis.c | 57 +++- > libdtrace/dt_open.c | 2 + > test/demo/builtin/ipl.d | 2 + > test/demo/builtin/vtimestamp.d | 2 + > test/demo/io/iocpu.d | 2 + > test/unittest/buffering/tst.cputime.sh | 1 + > test/unittest/disasm/tst.ann-bvar.r | 69 ++-- > test/unittest/disasm/tst.ann-bvar.sh | 9 +- > test/unittest/disasm/tst.vartab-bvar.r | 2 - > test/unittest/disasm/tst.vartab-bvar.sh | 7 +- > 13 files changed, 360 insertions(+), 245 deletions(-) > > diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c > index 1c0fa884..c760126d 100644 > --- a/bpf/get_bvar.c > +++ b/bpf/get_bvar.c > @@ -19,18 +19,21 @@ > # define noinline __attribute__((noinline)) > #endif > > -extern struct bpf_map_def cpuinfo; > -extern struct bpf_map_def probes; > -extern struct bpf_map_def state; > -extern struct bpf_map_def usdt_names; > - > -extern uint64_t PC; > -extern uint64_t STBSZ; > -extern uint64_t STKSIZ; > -extern uint64_t BOOTTM; > +extern struct bpf_map_def cpuinfo; > +extern struct bpf_map_def probes; > +extern struct bpf_map_def state; > +extern struct bpf_map_def usdt_names; > + > +extern uint64_t BOOTTM; > +extern uint64_t NPROBES; > +extern uint64_t PC; > +extern uint64_t STBSZ; > +extern uint64_t STKSIZ; > extern uint64_t STACK_OFF; > -extern uint64_t STACK_SKIP; > -extern uint64_t NPROBES; > +extern uint64_t STACK_SKIP; > +extern uint64_t TASK_COMM; > +extern uint64_t TASK_REAL_PARENT; > +extern uint64_t TASK_TGID; > > #define error(dctx, fault, illval) \ > ({ \ > @@ -38,198 +41,231 @@ extern uint64_t NPROBES; > -1; \ > }) > > -noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx) > +noinline uint64_t dt_bvar_args(const dt_dctx_t *dctx, uint32_t idx) > { > dt_mstate_t *mst = dctx->mst; > > - switch (id) { > - case DIF_VAR_CURTHREAD: > - return bpf_get_current_task(); > - case DIF_VAR_TIMESTAMP: > - if (mst->tstamp == 0) > - mst->tstamp = bpf_ktime_get_ns(); > + if (idx >= sizeof(mst->argv) / sizeof(mst->argv[0])) > + return error(dctx, DTRACEFLT_ILLOP, 0); > > - return mst->tstamp; > - case DIF_VAR_EPID: { > - return (((uint64_t)mst->prid) << 32) | mst->stid; > - } > - case DIF_VAR_ID: > - return mst->prid; > - case DIF_VAR_ARG0: case DIF_VAR_ARG1: case DIF_VAR_ARG2: > - case DIF_VAR_ARG3: case DIF_VAR_ARG4: case DIF_VAR_ARG5: > - case DIF_VAR_ARG6: case DIF_VAR_ARG7: case DIF_VAR_ARG8: > - case DIF_VAR_ARG9: > - return mst->argv[id - DIF_VAR_ARG0]; > - case DIF_VAR_ARGS: > - if (idx >= sizeof(mst->argv) / sizeof(mst->argv[0])) > - return error(dctx, DTRACEFLT_ILLOP, 0); > - > - return mst->argv[idx]; > - case DIF_VAR_STACKDEPTH: > - case DIF_VAR_USTACKDEPTH: { > - uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); > - uint64_t flags; > - char *buf = dctx->mem + (uint64_t)(&STACK_OFF); > - uint64_t stacksize; > - > - if (id == DIF_VAR_USTACKDEPTH) > - flags = BPF_F_USER_STACK; > - else > - flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK; > - > - stacksize = bpf_get_stack(dctx->ctx, buf, bufsiz, flags); > - if (stacksize < 0) > - return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); > + return mst->argv[idx]; > +} > + > +noinline uint64_t dt_bvar_caller(const dt_dctx_t *dctx) > +{ > + uint64_t buf[2] = { 0, }; > > + if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), > + (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK) < 0) > + return 0; > + > + return buf[1]; > +} > + > +noinline uint64_t dt_bvar_curcpu(const dt_dctx_t *dctx) > +{ > + uint32_t key = 0; > + void *val = bpf_map_lookup_elem(&cpuinfo, &key); > + > + if (val == NULL) { > /* > - * While linux/bpf.h does not describe the meaning of > - * bpf_get_stack()'s return value outside of its sign, > - * it is presumably the length of the copied stack. > - * > - * If stacksize==bufsiz, presumably the stack is larger than > - * what we can retrieve. But it's also possible that the > - * buffer was exactly large enough. So, leave it to the user > - * to interpret the result. > + * Typically, we would use 'return error(...);' but > + * that confuses the verifier because it returns -1. > + * So, instead, we explicitly return 0. > */ > - return stacksize / sizeof(uint64_t); > - } > - case DIF_VAR_CALLER: > - case DIF_VAR_UCALLER: { > - uint64_t flags; > - uint64_t buf[2] = { 0, }; > - > - if (id == DIF_VAR_UCALLER) > - flags = BPF_F_USER_STACK; > - else > - flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK; > - > - if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), flags) < 0) > - return 0; > - return buf[1]; > + error(dctx, DTRACEFLT_ILLOP, 0); > + return 0; > } > - case DIF_VAR_PROBEPROV: > - case DIF_VAR_PROBEMOD: > - case DIF_VAR_PROBEFUNC: > - case DIF_VAR_PROBENAME: { > - uint32_t key = mst->prid; > - > - if (key < ((uint64_t)&NPROBES)) { > - dt_bpf_probe_t *pinfo; > - uint64_t off; > - > - pinfo = bpf_map_lookup_elem(&probes, &key); > - if (pinfo == NULL) > - return (uint64_t)dctx->strtab; > - > - switch (id) { > - case DIF_VAR_PROBEPROV: > - off = pinfo->prv; > - break; > - case DIF_VAR_PROBEMOD: > - off = pinfo->mod; > - break; > - case DIF_VAR_PROBEFUNC: > - off = pinfo->fun; > - break; > - case DIF_VAR_PROBENAME: > - off = pinfo->prb; > - } > - if (off > (uint64_t)&STBSZ) > - return (uint64_t)dctx->strtab; > - > - return (uint64_t)(dctx->strtab + off); > - } else { > - char *s; > - > - s = bpf_map_lookup_elem(&usdt_names, &key); > - if (s == NULL) > - return (uint64_t)dctx->strtab; > - > - switch (id) { > - case DIF_VAR_PROBENAME: > - s += DTRACE_FUNCNAMELEN; > - case DIF_VAR_PROBEFUNC: > - s += DTRACE_MODNAMELEN; > - case DIF_VAR_PROBEMOD: > - s += DTRACE_PROVNAMELEN; > - case DIF_VAR_PROBEPROV: > - } > - > - return (uint64_t)s; > - } > - } > - case DIF_VAR_PID: { > - uint64_t val = bpf_get_current_pid_tgid(); > > - return val >> 32; > - } > - case DIF_VAR_TID: { > - uint64_t val = bpf_get_current_pid_tgid(); > + return (uint64_t)val; > +} > > - return val & 0x00000000ffffffffUL; > - } > - case DIF_VAR_EXECNAME: { > - uint64_t ptr; > - extern uint64_t TASK_COMM; > +noinline uint64_t dt_bvar_curthread(const dt_dctx_t *dctx) > +{ > + return bpf_get_current_task(); > +} > > - /* &(current->comm) */ > - ptr = bpf_get_current_task(); > - if (ptr == 0) > - return error(dctx, DTRACEFLT_BADADDR, ptr); > +noinline uint64_t dt_bvar_epid(const dt_dctx_t *dctx) > +{ > + dt_mstate_t *mst = dctx->mst; > > - return (uint64_t)ptr + (uint64_t)&TASK_COMM; > - } > - case DIF_VAR_WALLTIMESTAMP: > - return bpf_ktime_get_ns() + ((uint64_t)&BOOTTM); > - case DIF_VAR_PPID: { > - uint64_t ptr; > - int32_t val = -1; > - extern uint64_t TASK_REAL_PARENT; > - extern uint64_t TASK_TGID; > - > - /* Chase pointers val = current->real_parent->tgid. */ > - ptr = bpf_get_current_task(); > - if (ptr == 0) > - return error(dctx, DTRACEFLT_BADADDR, ptr); > - if (bpf_probe_read((void *)&ptr, 8, > - (const void *)(ptr + (uint64_t)&TASK_REAL_PARENT))) > - return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_REAL_PARENT); > - if (bpf_probe_read((void *)&val, 4, > - (const void *)(ptr + (uint64_t)&TASK_TGID))) > - return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_TGID); > - > - return (uint64_t)val; > - } > - case DIF_VAR_UID: { > - uint64_t val = bpf_get_current_uid_gid(); > + return (((uint64_t)mst->prid) << 32) | mst->stid; > +} > > - return val & 0x00000000ffffffffUL; > - } > - case DIF_VAR_GID: { > - uint64_t val = bpf_get_current_uid_gid(); > +noinline uint64_t dt_bvar_errno(const dt_dctx_t *dctx) > +{ > + dt_mstate_t *mst = dctx->mst; > > - return val >> 32; > - } > - case DIF_VAR_ERRNO: > - return mst->syscall_errno; > - case DIF_VAR_CURCPU: { > - uint32_t key = 0; > - void *val = bpf_map_lookup_elem(&cpuinfo, &key); > - > - if (val == NULL) { > - /* > - * Typically, we would use 'return error(...);' but > - * that confuses the verifier because it returns -1. > - * So, instead, we explicitly return 0. > - */ > - error(dctx, DTRACEFLT_ILLOP, 0); > - return 0; > + return mst->syscall_errno; > +} > + > +noinline uint64_t dt_bvar_execname(const dt_dctx_t *dctx) > +{ > + uint64_t ptr; > + > + /* &(current->comm) */ > + ptr = bpf_get_current_task(); > + if (ptr == 0) > + return error(dctx, DTRACEFLT_BADADDR, ptr); > + > + return (uint64_t)ptr + (uint64_t)&TASK_COMM; > +} > + > +noinline uint64_t dt_bvar_gid(const dt_dctx_t *dctx) > +{ > + return bpf_get_current_uid_gid() >> 32; > +} > + > +noinline uint64_t dt_bvar_id(const dt_dctx_t *dctx) > +{ > + dt_mstate_t *mst = dctx->mst; > + > + return mst->prid; > +} > + > +noinline uint64_t dt_bvar_pid(const dt_dctx_t *dctx) > +{ > + return bpf_get_current_pid_tgid() >> 32; > +} > + > +noinline uint64_t dt_bvar_ppid(const dt_dctx_t *dctx) > +{ > + uint64_t ptr; > + int32_t val = -1; > + > + /* Chase pointers val = current->real_parent->tgid. */ > + ptr = bpf_get_current_task(); > + if (ptr == 0) > + return error(dctx, DTRACEFLT_BADADDR, ptr); > + if (bpf_probe_read((void *)&ptr, 8, > + (const void *)(ptr + (uint64_t)&TASK_REAL_PARENT))) > + return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_REAL_PARENT); > + if (bpf_probe_read((void *)&val, 4, > + (const void *)(ptr + (uint64_t)&TASK_TGID))) > + return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_TGID); > + > + return (uint64_t)val; > +} > + > +noinline uint64_t dt_bvar_probedesc(const dt_dctx_t *dctx, uint32_t idx) > +{ > + dt_mstate_t *mst = dctx->mst; > + uint32_t key = mst->prid; > + > + if (key < ((uint64_t)&NPROBES)) { > + dt_bpf_probe_t *pinfo; > + uint64_t off = 0; > + > + pinfo = bpf_map_lookup_elem(&probes, &key); > + if (pinfo == NULL) > + return (uint64_t)dctx->strtab; > + > + switch (idx) { > + case DIF_VAR_PROBEPROV: > + off = pinfo->prv; > + break; > + case DIF_VAR_PROBEMOD: > + off = pinfo->mod; > + break; > + case DIF_VAR_PROBEFUNC: > + off = pinfo->fun; > + break; > + case DIF_VAR_PROBENAME: > + off = pinfo->prb; > } > + if (off > (uint64_t)&STBSZ) > + return (uint64_t)dctx->strtab; > > - return (uint64_t)val; > - } > - default: > - /* Not implemented yet. */ > - return error(dctx, DTRACEFLT_ILLOP, 0); > + return (uint64_t)(dctx->strtab + off); > + } else { > + char *s; > + > + s = bpf_map_lookup_elem(&usdt_names, &key); > + if (s == NULL) > + return (uint64_t)dctx->strtab; > + > + switch (idx) { > + case DIF_VAR_PROBEPROV: > + s += DTRACE_FUNCNAMELEN; > + case DIF_VAR_PROBEMOD: > + s += DTRACE_MODNAMELEN; > + case DIF_VAR_PROBEFUNC: > + s += DTRACE_PROVNAMELEN; > + case DIF_VAR_PROBENAME: > + } > + > + return (uint64_t)s; > } > } > + > +noinline uint64_t dt_bvar_stackdepth(const dt_dctx_t *dctx) > +{ > + uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); > + char *buf = dctx->mem + (uint64_t)(&STACK_OFF); > + uint64_t retv; > + > + retv = bpf_get_stack(dctx->ctx, buf, bufsiz, > + (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK); > + if (retv < 0) > + return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); > + > + /* > + * While linux/bpf.h does not describe the meaning of bpf_get_stack()'s > + * return value outside of its sign, it is presumably the length of the > + * copied stack. > + * > + * If retv==bufsiz, presumably the stack is larger than what we > + * can retrieve. But it's also possible that the buffer was exactly > + * large enough. So, leave it to the user to interpret the result. > + */ > + return retv / sizeof(uint64_t); > +} > + > +noinline uint64_t dt_bvar_tid(const dt_dctx_t *dctx) > +{ > + return bpf_get_current_pid_tgid() & 0x00000000ffffffffUL; > +} > + > +noinline uint64_t dt_bvar_timestamp(const dt_dctx_t *dctx) > +{ > + dt_mstate_t *mst = dctx->mst; > + > + if (mst->tstamp == 0) > + mst->tstamp = bpf_ktime_get_ns(); > + > + return mst->tstamp; > +} > + > +noinline uint64_t dt_bvar_ucaller(const dt_dctx_t *dctx) > +{ > + uint64_t buf[2] = { 0, }; > + > + if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), BPF_F_USER_STACK) < 0) > + return 0; > + > + return buf[1]; > +} > + > +noinline uint64_t dt_bvar_uid(const dt_dctx_t *dctx) > +{ > + return bpf_get_current_uid_gid() & 0x00000000ffffffffUL; > +} > + > +noinline uint64_t dt_bvar_ustackdepth(const dt_dctx_t *dctx) > +{ > + uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); > + char *buf = dctx->mem + (uint64_t)(&STACK_OFF); > + uint64_t retv; > + > + retv = bpf_get_stack(dctx->ctx, buf, bufsiz, BPF_F_USER_STACK); > + if (retv < 0) > + return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); > + > + /* See dt_bvar_stackdepth() above. */ > + return retv / sizeof(uint64_t); > +} > + > +noinline uint64_t dt_bvar_walltimestamp(const dt_dctx_t *dctx) > +{ > + return bpf_ktime_get_ns() + ((uint64_t)&BOOTTM); > +} > diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h > index c8c1d961..9f6e3b55 100644 > --- a/include/dtrace/dif_defines.h > +++ b/include/dtrace/dif_defines.h > @@ -162,6 +162,7 @@ > #define DIF_VAR_GID 0x011f > #define DIF_VAR_ERRNO 0x0120 > #define DIF_VAR_CURCPU 0x0121 > +#define DIF_VAR_EXECARGS 0x0122 > > #define DIF_SUBR_RAND 0 > #define DIF_SUBR_MUTEX_OWNED 1 > diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c > index e7e3a132..6e74b4b0 100644 > --- a/libdtrace/dt_cg.c > +++ b/libdtrace/dt_cg.c > @@ -3197,6 +3197,7 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > { > dt_ident_t *idp = dt_ident_resolve(dnp->dn_ident); > dt_ident_t *fnp; > + uint32_t idx = UINT32_MAX; > > idp->di_flags |= DT_IDFLG_DIFR; > > @@ -3298,15 +3299,38 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > return; > } > > - /* built-in variables */ > + /* built-in variables (note: args[] is handled in dt_cg_array_op) */ > + /* Special case for arg0 through arg9; encode as args[n] */ > + if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { > + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); > + idx = idp->di_id - DIF_VAR_ARG0; > + } else if (idp->di_id == DIF_VAR_PROBEPROV || > + idp->di_id == DIF_VAR_PROBEMOD || > + idp->di_id == DIF_VAR_PROBEFUNC || > + idp->di_id == DIF_VAR_PROBENAME) { > + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_probedesc"); > + idx = idp->di_id; > + } else { > + char *fn; > + > + if (asprintf(&fn, "dt_bvar_%s", idp->di_name) == -1) > + longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); > + > + fnp = dt_dlib_get_func(yypcb->pcb_hdl, fn); > + free(fn); > + } > + > + /* No implementing function found - report ILLOP. */ > + if (fnp == NULL) > + xyerror(D_IDENT_UNDEF, > + "built-in variable '%s' not implemented", idp->di_name); > + > if (dt_regset_xalloc_args(drp) == -1) > longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); > > dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1); > - emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id)); > - emit(dlp, BPF_MOV_IMM(BPF_REG_3, 0)); > - fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar"); > - assert(fnp != NULL); > + if (idx != UINT32_MAX) > + emit(dlp, BPF_MOV_IMM(BPF_REG_2, idx)); > dt_regset_xalloc(drp, BPF_REG_0); > emite(dlp, BPF_CALL_FUNC(fnp->di_id), fnp); > dt_regset_free_args(drp); > @@ -5065,7 +5089,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > dt_probe_t *prp = yypcb->pcb_probe; > uintmax_t saved = dnp->dn_args->dn_value; > dt_ident_t *idp = dnp->dn_ident; > - dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar"); > + dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); > size_t size; > int n; > int ustr = 0; > @@ -5135,8 +5159,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > if (dt_regset_xalloc_args(drp) == -1) > longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); > dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1); > - emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id)); > - emit(dlp, BPF_MOV_REG(BPF_REG_3, dnp->dn_reg)); > + emit(dlp, BPF_MOV_REG(BPF_REG_2, dnp->dn_reg)); > dt_regset_xalloc(drp, BPF_REG_0); > emite(dlp, BPF_CALL_FUNC(fidp->di_id), fidp); > dt_regset_free_args(drp); > diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c > index 9f319d70..d983c099 100644 > --- a/libdtrace/dt_dis.c > +++ b/libdtrace/dt_dis.c > @@ -364,16 +364,57 @@ static char * > dt_dis_bpf_args(const dtrace_difo_t *dp, const char *fn, > const struct bpf_insn *in, char *buf, size_t len, uint_t addr) > { > - if (strcmp(fn, "dt_get_bvar") == 0) { > + if (strcmp(fn, "dt_bvar_args") == 0) { > /* > - * We know that the previous two instructions exist and move > - * the variable id to a register in the first instruction of > - * that sequence (because we wrote the code generator to emit > - * the instructions in this exact order.) > + * We need to support two cases: > + * - access to argN: > + * lddw %r1, dctx > + * mov %r2, N > + * call dt_bvar_args > + * - access to args[N]: > + * mov %rX, N > + * lddw %r1, dctx > + * mov %r2, %rX > + * call dt_bvar_args > */ > - in -= 2; > - snprintf(buf, len, "%s", > - dt_dis_varname_id(dp, in->imm, DIFV_SCOPE_GLOBAL, addr)); > + in--; > + if (BPF_OP(in->code) == BPF_MOV && in->dst_reg == 2) { > + if (BPF_SRC(in->code) == BPF_K) { > + snprintf(buf, len, "arg%d", in->imm); > + return buf; > + } > + > + in -= 2; > + if (BPF_OP(in->code) == BPF_MOV && > + BPF_SRC(in->code) == BPF_K && > + in->dst_reg == in[2].src_reg) { > + snprintf(buf, len, "args[%d]", in->imm); > + return buf; > + } > + } > + > + snprintf(buf, len, "args[?]"); > + return buf; > + } else if (strcmp(fn, "dt_bvar_probedesc") == 0) { > + /* > + * Access to probe(prov|mod|func|name); > + * lddw %r1, dctx > + * mov %r2, N > + * call dt_bvar_probedesc > + */ > + in--; > + if (BPF_OP(in->code) == BPF_MOV && in->dst_reg == 2 && > + BPF_SRC(in->code) == BPF_K) { > + snprintf(buf, len, "%s", > + dt_dis_varname_id(dp, in->imm, > + DIFV_SCOPE_GLOBAL, addr)); > + return buf; > + } > + > + return NULL; > + } else if (strncmp(fn, "dt_bvar_", 8) == 0) { > + /* The variable name is in the function name.*/ > + snprintf(buf, len, "%s", fn + 8); > return buf; > } else if (strcmp(fn, "dt_get_agg") == 0) { > /* > diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c > index a0205887..51c056b2 100644 > --- a/libdtrace/dt_open.c > +++ b/libdtrace/dt_open.c > @@ -153,6 +153,8 @@ static const dt_ident_t _dtrace_globals[] = { > &dt_idops_type, "uint64_t" }, > { "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0, > &dt_idops_type, "int" }, > +{ "execargs", DT_IDENT_SCALAR, 0, DIF_VAR_EXECARGS, > + DT_ATTR_STABCMN, DT_VERS_2_0, &dt_idops_type, "string" }, > { "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME, > DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, > { "exit", DT_IDENT_ACTFUNC, 0, DT_ACT_EXIT, DT_ATTR_STABCMN, DT_VERS_1_0, > diff --git a/test/demo/builtin/ipl.d b/test/demo/builtin/ipl.d > index ca7f3bb7..f613bb70 100644 > --- a/test/demo/builtin/ipl.d > +++ b/test/demo/builtin/ipl.d > @@ -1,3 +1,5 @@ > +/* @@xfail: dtv2: need ipl support */ > + > BEGIN { > trace(ipl); > exit(0); > diff --git a/test/demo/builtin/vtimestamp.d b/test/demo/builtin/vtimestamp.d > index 9f01bbf0..fcb708d0 100644 > --- a/test/demo/builtin/vtimestamp.d > +++ b/test/demo/builtin/vtimestamp.d > @@ -1,3 +1,5 @@ > +/* @@xfail: dtv2: need vtimestamp support */ > + > BEGIN { > trace(vtimestamp); > exit(0); > diff --git a/test/demo/io/iocpu.d b/test/demo/io/iocpu.d > index c7b847e7..1230d6f6 100644 > --- a/test/demo/io/iocpu.d > +++ b/test/demo/io/iocpu.d > @@ -5,6 +5,8 @@ > * http://oss.oracle.com/licenses/upl. > */ > > +/* @@xfail: dtv2: need vtimestamp support */ > + > #pragma D option quiet > > sched:::on-cpu > diff --git a/test/unittest/buffering/tst.cputime.sh b/test/unittest/buffering/tst.cputime.sh > index 6a420e8d..c0e248a6 100755 > --- a/test/unittest/buffering/tst.cputime.sh > +++ b/test/unittest/buffering/tst.cputime.sh > @@ -5,6 +5,7 @@ > # Licensed under the Universal Permissive License v 1.0 as shown at > # http://oss.oracle.com/licenses/upl. > # > +# @@xfail: dtv2: need vtimestamp support > # @@timeout: 12 > > script() > diff --git a/test/unittest/disasm/tst.ann-bvar.r b/test/unittest/disasm/tst.ann-bvar.r > index b514dd99..a55fb6de 100644 > --- a/test/unittest/disasm/tst.ann-bvar.r > +++ b/test/unittest/disasm/tst.ann-bvar.r > @@ -1,34 +1,35 @@ > -85 0 1 0000 ffffffff call dt_get_bvar ! arg0 > -85 0 1 0000 ffffffff call dt_get_bvar ! arg1 > -85 0 1 0000 ffffffff call dt_get_bvar ! arg2 > -85 0 1 0000 ffffffff call dt_get_bvar ! arg3 > -85 0 1 0000 ffffffff call dt_get_bvar ! arg4 > -85 0 1 0000 ffffffff call dt_get_bvar ! arg5 > -85 0 1 0000 ffffffff call dt_get_bvar ! arg6 > -85 0 1 0000 ffffffff call dt_get_bvar ! arg7 > -85 0 1 0000 ffffffff call dt_get_bvar ! arg8 > -85 0 1 0000 ffffffff call dt_get_bvar ! arg9 > -85 0 1 0000 ffffffff call dt_get_bvar ! args > -85 0 1 0000 ffffffff call dt_get_bvar ! caller > -85 0 1 0000 ffffffff call dt_get_bvar ! curcpu > -85 0 1 0000 ffffffff call dt_get_bvar ! curthread > -85 0 1 0000 ffffffff call dt_get_bvar ! epid > -85 0 1 0000 ffffffff call dt_get_bvar ! errno > -85 0 1 0000 ffffffff call dt_get_bvar ! execname > -85 0 1 0000 ffffffff call dt_get_bvar ! gid > -85 0 1 0000 ffffffff call dt_get_bvar ! id > -85 0 1 0000 ffffffff call dt_get_bvar ! ipl > -85 0 1 0000 ffffffff call dt_get_bvar ! pid > -85 0 1 0000 ffffffff call dt_get_bvar ! ppid > -85 0 1 0000 ffffffff call dt_get_bvar ! probefunc > -85 0 1 0000 ffffffff call dt_get_bvar ! probemod > -85 0 1 0000 ffffffff call dt_get_bvar ! probename > -85 0 1 0000 ffffffff call dt_get_bvar ! probeprov > -85 0 1 0000 ffffffff call dt_get_bvar ! stackdepth > -85 0 1 0000 ffffffff call dt_get_bvar ! tid > -85 0 1 0000 ffffffff call dt_get_bvar ! timestamp > -85 0 1 0000 ffffffff call dt_get_bvar ! ucaller > -85 0 1 0000 ffffffff call dt_get_bvar ! uid > -85 0 1 0000 ffffffff call dt_get_bvar ! ustackdepth > -85 0 1 0000 ffffffff call dt_get_bvar ! vtimestamp > -85 0 1 0000 ffffffff call dt_get_bvar ! walltimestamp > +85 0 1 0000 ffffffff call dt_bvar_args ! arg0 > +85 0 1 0000 ffffffff call dt_bvar_args ! arg1 > +85 0 1 0000 ffffffff call dt_bvar_args ! arg2 > +85 0 1 0000 ffffffff call dt_bvar_args ! arg3 > +85 0 1 0000 ffffffff call dt_bvar_args ! arg4 > +85 0 1 0000 ffffffff call dt_bvar_args ! arg5 > +85 0 1 0000 ffffffff call dt_bvar_args ! arg6 > +85 0 1 0000 ffffffff call dt_bvar_args ! arg7 > +85 0 1 0000 ffffffff call dt_bvar_args ! arg8 > +85 0 1 0000 ffffffff call dt_bvar_args ! arg9 > +85 0 1 0000 ffffffff call dt_bvar_args ! args[0] > +85 0 1 0000 ffffffff call dt_bvar_args ! args[1] > +85 0 1 0000 ffffffff call dt_bvar_args ! args[2] > +85 0 1 0000 ffffffff call dt_bvar_args ! args[3] > +85 0 1 0000 ffffffff call dt_bvar_caller ! caller > +85 0 1 0000 ffffffff call dt_bvar_curcpu ! curcpu > +85 0 1 0000 ffffffff call dt_bvar_curthread ! curthread > +85 0 1 0000 ffffffff call dt_bvar_epid ! epid > +85 0 1 0000 ffffffff call dt_bvar_errno ! errno > +85 0 1 0000 ffffffff call dt_bvar_execname ! execname > +85 0 1 0000 ffffffff call dt_bvar_gid ! gid > +85 0 1 0000 ffffffff call dt_bvar_id ! id > +85 0 1 0000 ffffffff call dt_bvar_pid ! pid > +85 0 1 0000 ffffffff call dt_bvar_ppid ! ppid > +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probefunc > +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probemod > +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probename > +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probeprov > +85 0 1 0000 ffffffff call dt_bvar_stackdepth ! stackdepth > +85 0 1 0000 ffffffff call dt_bvar_tid ! tid > +85 0 1 0000 ffffffff call dt_bvar_timestamp ! timestamp > +85 0 1 0000 ffffffff call dt_bvar_ucaller ! ucaller > +85 0 1 0000 ffffffff call dt_bvar_uid ! uid > +85 0 1 0000 ffffffff call dt_bvar_ustackdepth ! ustackdepth > +85 0 1 0000 ffffffff call dt_bvar_walltimestamp ! walltimestamp > diff --git a/test/unittest/disasm/tst.ann-bvar.sh b/test/unittest/disasm/tst.ann-bvar.sh > index 6dc43424..61e838d1 100755 > --- a/test/unittest/disasm/tst.ann-bvar.sh > +++ b/test/unittest/disasm/tst.ann-bvar.sh > @@ -22,6 +22,9 @@ sdt:task::task_rename > trace(arg8); > trace(arg9); > trace(args[0]); > + trace(args[1]); > + trace(args[2]); > + trace(args[3]); > trace(caller); > trace(curcpu); > trace(curthread); > @@ -30,7 +33,7 @@ sdt:task::task_rename > trace(execname); > trace(gid); > trace(id); > - trace(ipl); > +/* trace(ipl); */ > trace(pid); > trace(ppid); > trace(probefunc); > @@ -43,10 +46,10 @@ sdt:task::task_rename > trace(ucaller); > trace(uid); > trace(ustackdepth); > - trace(vtimestamp); > +/* trace(vtimestamp); */ > trace(walltimestamp); > exit(0); > } > -' 2>&1 | gawk '/ call dt_get_bvar/ { sub(/^[^:]+: /, ""); print; }' > +' 2>&1 | gawk '/ call dt_bvar_/ { sub(/^[^:]+: /, ""); print; }' > > exit $? > diff --git a/test/unittest/disasm/tst.vartab-bvar.r b/test/unittest/disasm/tst.vartab-bvar.r > index 53e5f618..04fa3a8d 100644 > --- a/test/unittest/disasm/tst.vartab-bvar.r > +++ b/test/unittest/disasm/tst.vartab-bvar.r > @@ -2,8 +2,6 @@ NAME OFFSET KND SCP FLAG TYPE > args arr glb r any (unknown) by ref (size 0) > 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 8) > id scl glb r D type (integer) (size 4) > arg0 scl glb r D type (integer) (size 8) > diff --git a/test/unittest/disasm/tst.vartab-bvar.sh b/test/unittest/disasm/tst.vartab-bvar.sh > index 098c1f45..ce489a24 100755 > --- a/test/unittest/disasm/tst.vartab-bvar.sh > +++ b/test/unittest/disasm/tst.vartab-bvar.sh > @@ -30,6 +30,9 @@ sdt:task::task_rename > trace(arg8); > trace(arg9); > trace(args[0]); > + trace(args[1]); > + trace(args[2]); > + trace(args[3]); > trace(caller); > trace(curcpu); > trace(curthread); > @@ -38,7 +41,7 @@ sdt:task::task_rename > trace(execname); > trace(gid); > trace(id); > - trace(ipl); > +/* trace(ipl); */ > trace(pid); > trace(ppid); > trace(probefunc); > @@ -52,7 +55,7 @@ sdt:task::task_rename > trace(uid); > /* trace(uregs[0]); */ /* test this separately until uregs[0] works on all kernels */ > trace(ustackdepth); > - trace(vtimestamp); > +/* trace(vtimestamp); */ > trace(walltimestamp); > exit(0); > } From kris.van.hees at oracle.com Fri Jan 24 16:56:01 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Fri, 24 Jan 2025 11:56:01 -0500 Subject: [DTrace-devel] [PATCH] bpf: separate bvar implementation into separate functions In-Reply-To: <252a8cc4-0bcc-a41c-997d-f5c264c1ed1c@oracle.com> References: <252a8cc4-0bcc-a41c-997d-f5c264c1ed1c@oracle.com> Message-ID: On Fri, Jan 24, 2025 at 02:35:49AM -0500, Eugene Loh wrote: > I think I'm on board with this patch, but two questions. > > 1.? There is DIF_VAR_EXECARGS stuff in two places.? Is that stuff in the > wrong patch? Oops, yes, that is for a follow-up patch. WIll adjust. > 2.? I'm confused why > ? ?? ?? test/demo/builtin/ipl.d > ??????? test/demo/builtin/vtimestamp.d > were passing:? there was no ipl or vtimestamp support before and there is > none now.? Presumably, the tests used to time out... so why was that > considered a PASS?? I guess I see why test/unittest/buffering/tst.cputime.sh > used to pass, but maybe that suggests that the test needs to be tightened up > and be made quite a bit more discriminating. The test/demo cases are all mostly pointless, especially because e.g. these PASSes came from the test/demo/test.options containing "@@timeout-success". We should probably just remove the test/demo cases from the actual testsuite, and leave them around (for now) as examples (and overall not very good ones at that). > On 1/23/25 22:48, Kris Van Hees wrote: > > The handling of builtin variables was done with a single big function > > that therefore got linked into every single BPF program (twice if the > > builtin variable might raise a fault). Providing separate functions > > for most builtin variables reduces BPF program size significantly. > > > > This also reduces pressure on the BPF verifies. > > > > Signed-off-by: Kris Van Hees > > --- > > bpf/get_bvar.c | 412 +++++++++++++----------- > > include/dtrace/dif_defines.h | 1 + > > libdtrace/dt_cg.c | 39 ++- > > libdtrace/dt_dis.c | 57 +++- > > libdtrace/dt_open.c | 2 + > > test/demo/builtin/ipl.d | 2 + > > test/demo/builtin/vtimestamp.d | 2 + > > test/demo/io/iocpu.d | 2 + > > test/unittest/buffering/tst.cputime.sh | 1 + > > test/unittest/disasm/tst.ann-bvar.r | 69 ++-- > > test/unittest/disasm/tst.ann-bvar.sh | 9 +- > > test/unittest/disasm/tst.vartab-bvar.r | 2 - > > test/unittest/disasm/tst.vartab-bvar.sh | 7 +- > > 13 files changed, 360 insertions(+), 245 deletions(-) > > > > diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c > > index 1c0fa884..c760126d 100644 > > --- a/bpf/get_bvar.c > > +++ b/bpf/get_bvar.c > > @@ -19,18 +19,21 @@ > > # define noinline __attribute__((noinline)) > > #endif > > -extern struct bpf_map_def cpuinfo; > > -extern struct bpf_map_def probes; > > -extern struct bpf_map_def state; > > -extern struct bpf_map_def usdt_names; > > - > > -extern uint64_t PC; > > -extern uint64_t STBSZ; > > -extern uint64_t STKSIZ; > > -extern uint64_t BOOTTM; > > +extern struct bpf_map_def cpuinfo; > > +extern struct bpf_map_def probes; > > +extern struct bpf_map_def state; > > +extern struct bpf_map_def usdt_names; > > + > > +extern uint64_t BOOTTM; > > +extern uint64_t NPROBES; > > +extern uint64_t PC; > > +extern uint64_t STBSZ; > > +extern uint64_t STKSIZ; > > extern uint64_t STACK_OFF; > > -extern uint64_t STACK_SKIP; > > -extern uint64_t NPROBES; > > +extern uint64_t STACK_SKIP; > > +extern uint64_t TASK_COMM; > > +extern uint64_t TASK_REAL_PARENT; > > +extern uint64_t TASK_TGID; > > #define error(dctx, fault, illval) \ > > ({ \ > > @@ -38,198 +41,231 @@ extern uint64_t NPROBES; > > -1; \ > > }) > > -noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx) > > +noinline uint64_t dt_bvar_args(const dt_dctx_t *dctx, uint32_t idx) > > { > > dt_mstate_t *mst = dctx->mst; > > - switch (id) { > > - case DIF_VAR_CURTHREAD: > > - return bpf_get_current_task(); > > - case DIF_VAR_TIMESTAMP: > > - if (mst->tstamp == 0) > > - mst->tstamp = bpf_ktime_get_ns(); > > + if (idx >= sizeof(mst->argv) / sizeof(mst->argv[0])) > > + return error(dctx, DTRACEFLT_ILLOP, 0); > > - return mst->tstamp; > > - case DIF_VAR_EPID: { > > - return (((uint64_t)mst->prid) << 32) | mst->stid; > > - } > > - case DIF_VAR_ID: > > - return mst->prid; > > - case DIF_VAR_ARG0: case DIF_VAR_ARG1: case DIF_VAR_ARG2: > > - case DIF_VAR_ARG3: case DIF_VAR_ARG4: case DIF_VAR_ARG5: > > - case DIF_VAR_ARG6: case DIF_VAR_ARG7: case DIF_VAR_ARG8: > > - case DIF_VAR_ARG9: > > - return mst->argv[id - DIF_VAR_ARG0]; > > - case DIF_VAR_ARGS: > > - if (idx >= sizeof(mst->argv) / sizeof(mst->argv[0])) > > - return error(dctx, DTRACEFLT_ILLOP, 0); > > - > > - return mst->argv[idx]; > > - case DIF_VAR_STACKDEPTH: > > - case DIF_VAR_USTACKDEPTH: { > > - uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); > > - uint64_t flags; > > - char *buf = dctx->mem + (uint64_t)(&STACK_OFF); > > - uint64_t stacksize; > > - > > - if (id == DIF_VAR_USTACKDEPTH) > > - flags = BPF_F_USER_STACK; > > - else > > - flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK; > > - > > - stacksize = bpf_get_stack(dctx->ctx, buf, bufsiz, flags); > > - if (stacksize < 0) > > - return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); > > + return mst->argv[idx]; > > +} > > + > > +noinline uint64_t dt_bvar_caller(const dt_dctx_t *dctx) > > +{ > > + uint64_t buf[2] = { 0, }; > > + if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), > > + (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK) < 0) > > + return 0; > > + > > + return buf[1]; > > +} > > + > > +noinline uint64_t dt_bvar_curcpu(const dt_dctx_t *dctx) > > +{ > > + uint32_t key = 0; > > + void *val = bpf_map_lookup_elem(&cpuinfo, &key); > > + > > + if (val == NULL) { > > /* > > - * While linux/bpf.h does not describe the meaning of > > - * bpf_get_stack()'s return value outside of its sign, > > - * it is presumably the length of the copied stack. > > - * > > - * If stacksize==bufsiz, presumably the stack is larger than > > - * what we can retrieve. But it's also possible that the > > - * buffer was exactly large enough. So, leave it to the user > > - * to interpret the result. > > + * Typically, we would use 'return error(...);' but > > + * that confuses the verifier because it returns -1. > > + * So, instead, we explicitly return 0. > > */ > > - return stacksize / sizeof(uint64_t); > > - } > > - case DIF_VAR_CALLER: > > - case DIF_VAR_UCALLER: { > > - uint64_t flags; > > - uint64_t buf[2] = { 0, }; > > - > > - if (id == DIF_VAR_UCALLER) > > - flags = BPF_F_USER_STACK; > > - else > > - flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK; > > - > > - if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), flags) < 0) > > - return 0; > > - return buf[1]; > > + error(dctx, DTRACEFLT_ILLOP, 0); > > + return 0; > > } > > - case DIF_VAR_PROBEPROV: > > - case DIF_VAR_PROBEMOD: > > - case DIF_VAR_PROBEFUNC: > > - case DIF_VAR_PROBENAME: { > > - uint32_t key = mst->prid; > > - > > - if (key < ((uint64_t)&NPROBES)) { > > - dt_bpf_probe_t *pinfo; > > - uint64_t off; > > - > > - pinfo = bpf_map_lookup_elem(&probes, &key); > > - if (pinfo == NULL) > > - return (uint64_t)dctx->strtab; > > - > > - switch (id) { > > - case DIF_VAR_PROBEPROV: > > - off = pinfo->prv; > > - break; > > - case DIF_VAR_PROBEMOD: > > - off = pinfo->mod; > > - break; > > - case DIF_VAR_PROBEFUNC: > > - off = pinfo->fun; > > - break; > > - case DIF_VAR_PROBENAME: > > - off = pinfo->prb; > > - } > > - if (off > (uint64_t)&STBSZ) > > - return (uint64_t)dctx->strtab; > > - > > - return (uint64_t)(dctx->strtab + off); > > - } else { > > - char *s; > > - > > - s = bpf_map_lookup_elem(&usdt_names, &key); > > - if (s == NULL) > > - return (uint64_t)dctx->strtab; > > - > > - switch (id) { > > - case DIF_VAR_PROBENAME: > > - s += DTRACE_FUNCNAMELEN; > > - case DIF_VAR_PROBEFUNC: > > - s += DTRACE_MODNAMELEN; > > - case DIF_VAR_PROBEMOD: > > - s += DTRACE_PROVNAMELEN; > > - case DIF_VAR_PROBEPROV: > > - } > > - > > - return (uint64_t)s; > > - } > > - } > > - case DIF_VAR_PID: { > > - uint64_t val = bpf_get_current_pid_tgid(); > > - return val >> 32; > > - } > > - case DIF_VAR_TID: { > > - uint64_t val = bpf_get_current_pid_tgid(); > > + return (uint64_t)val; > > +} > > - return val & 0x00000000ffffffffUL; > > - } > > - case DIF_VAR_EXECNAME: { > > - uint64_t ptr; > > - extern uint64_t TASK_COMM; > > +noinline uint64_t dt_bvar_curthread(const dt_dctx_t *dctx) > > +{ > > + return bpf_get_current_task(); > > +} > > - /* &(current->comm) */ > > - ptr = bpf_get_current_task(); > > - if (ptr == 0) > > - return error(dctx, DTRACEFLT_BADADDR, ptr); > > +noinline uint64_t dt_bvar_epid(const dt_dctx_t *dctx) > > +{ > > + dt_mstate_t *mst = dctx->mst; > > - return (uint64_t)ptr + (uint64_t)&TASK_COMM; > > - } > > - case DIF_VAR_WALLTIMESTAMP: > > - return bpf_ktime_get_ns() + ((uint64_t)&BOOTTM); > > - case DIF_VAR_PPID: { > > - uint64_t ptr; > > - int32_t val = -1; > > - extern uint64_t TASK_REAL_PARENT; > > - extern uint64_t TASK_TGID; > > - > > - /* Chase pointers val = current->real_parent->tgid. */ > > - ptr = bpf_get_current_task(); > > - if (ptr == 0) > > - return error(dctx, DTRACEFLT_BADADDR, ptr); > > - if (bpf_probe_read((void *)&ptr, 8, > > - (const void *)(ptr + (uint64_t)&TASK_REAL_PARENT))) > > - return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_REAL_PARENT); > > - if (bpf_probe_read((void *)&val, 4, > > - (const void *)(ptr + (uint64_t)&TASK_TGID))) > > - return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_TGID); > > - > > - return (uint64_t)val; > > - } > > - case DIF_VAR_UID: { > > - uint64_t val = bpf_get_current_uid_gid(); > > + return (((uint64_t)mst->prid) << 32) | mst->stid; > > +} > > - return val & 0x00000000ffffffffUL; > > - } > > - case DIF_VAR_GID: { > > - uint64_t val = bpf_get_current_uid_gid(); > > +noinline uint64_t dt_bvar_errno(const dt_dctx_t *dctx) > > +{ > > + dt_mstate_t *mst = dctx->mst; > > - return val >> 32; > > - } > > - case DIF_VAR_ERRNO: > > - return mst->syscall_errno; > > - case DIF_VAR_CURCPU: { > > - uint32_t key = 0; > > - void *val = bpf_map_lookup_elem(&cpuinfo, &key); > > - > > - if (val == NULL) { > > - /* > > - * Typically, we would use 'return error(...);' but > > - * that confuses the verifier because it returns -1. > > - * So, instead, we explicitly return 0. > > - */ > > - error(dctx, DTRACEFLT_ILLOP, 0); > > - return 0; > > + return mst->syscall_errno; > > +} > > + > > +noinline uint64_t dt_bvar_execname(const dt_dctx_t *dctx) > > +{ > > + uint64_t ptr; > > + > > + /* &(current->comm) */ > > + ptr = bpf_get_current_task(); > > + if (ptr == 0) > > + return error(dctx, DTRACEFLT_BADADDR, ptr); > > + > > + return (uint64_t)ptr + (uint64_t)&TASK_COMM; > > +} > > + > > +noinline uint64_t dt_bvar_gid(const dt_dctx_t *dctx) > > +{ > > + return bpf_get_current_uid_gid() >> 32; > > +} > > + > > +noinline uint64_t dt_bvar_id(const dt_dctx_t *dctx) > > +{ > > + dt_mstate_t *mst = dctx->mst; > > + > > + return mst->prid; > > +} > > + > > +noinline uint64_t dt_bvar_pid(const dt_dctx_t *dctx) > > +{ > > + return bpf_get_current_pid_tgid() >> 32; > > +} > > + > > +noinline uint64_t dt_bvar_ppid(const dt_dctx_t *dctx) > > +{ > > + uint64_t ptr; > > + int32_t val = -1; > > + > > + /* Chase pointers val = current->real_parent->tgid. */ > > + ptr = bpf_get_current_task(); > > + if (ptr == 0) > > + return error(dctx, DTRACEFLT_BADADDR, ptr); > > + if (bpf_probe_read((void *)&ptr, 8, > > + (const void *)(ptr + (uint64_t)&TASK_REAL_PARENT))) > > + return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_REAL_PARENT); > > + if (bpf_probe_read((void *)&val, 4, > > + (const void *)(ptr + (uint64_t)&TASK_TGID))) > > + return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_TGID); > > + > > + return (uint64_t)val; > > +} > > + > > +noinline uint64_t dt_bvar_probedesc(const dt_dctx_t *dctx, uint32_t idx) > > +{ > > + dt_mstate_t *mst = dctx->mst; > > + uint32_t key = mst->prid; > > + > > + if (key < ((uint64_t)&NPROBES)) { > > + dt_bpf_probe_t *pinfo; > > + uint64_t off = 0; > > + > > + pinfo = bpf_map_lookup_elem(&probes, &key); > > + if (pinfo == NULL) > > + return (uint64_t)dctx->strtab; > > + > > + switch (idx) { > > + case DIF_VAR_PROBEPROV: > > + off = pinfo->prv; > > + break; > > + case DIF_VAR_PROBEMOD: > > + off = pinfo->mod; > > + break; > > + case DIF_VAR_PROBEFUNC: > > + off = pinfo->fun; > > + break; > > + case DIF_VAR_PROBENAME: > > + off = pinfo->prb; > > } > > + if (off > (uint64_t)&STBSZ) > > + return (uint64_t)dctx->strtab; > > - return (uint64_t)val; > > - } > > - default: > > - /* Not implemented yet. */ > > - return error(dctx, DTRACEFLT_ILLOP, 0); > > + return (uint64_t)(dctx->strtab + off); > > + } else { > > + char *s; > > + > > + s = bpf_map_lookup_elem(&usdt_names, &key); > > + if (s == NULL) > > + return (uint64_t)dctx->strtab; > > + > > + switch (idx) { > > + case DIF_VAR_PROBEPROV: > > + s += DTRACE_FUNCNAMELEN; > > + case DIF_VAR_PROBEMOD: > > + s += DTRACE_MODNAMELEN; > > + case DIF_VAR_PROBEFUNC: > > + s += DTRACE_PROVNAMELEN; > > + case DIF_VAR_PROBENAME: > > + } > > + > > + return (uint64_t)s; > > } > > } > > + > > +noinline uint64_t dt_bvar_stackdepth(const dt_dctx_t *dctx) > > +{ > > + uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); > > + char *buf = dctx->mem + (uint64_t)(&STACK_OFF); > > + uint64_t retv; > > + > > + retv = bpf_get_stack(dctx->ctx, buf, bufsiz, > > + (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK); > > + if (retv < 0) > > + return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); > > + > > + /* > > + * While linux/bpf.h does not describe the meaning of bpf_get_stack()'s > > + * return value outside of its sign, it is presumably the length of the > > + * copied stack. > > + * > > + * If retv==bufsiz, presumably the stack is larger than what we > > + * can retrieve. But it's also possible that the buffer was exactly > > + * large enough. So, leave it to the user to interpret the result. > > + */ > > + return retv / sizeof(uint64_t); > > +} > > + > > +noinline uint64_t dt_bvar_tid(const dt_dctx_t *dctx) > > +{ > > + return bpf_get_current_pid_tgid() & 0x00000000ffffffffUL; > > +} > > + > > +noinline uint64_t dt_bvar_timestamp(const dt_dctx_t *dctx) > > +{ > > + dt_mstate_t *mst = dctx->mst; > > + > > + if (mst->tstamp == 0) > > + mst->tstamp = bpf_ktime_get_ns(); > > + > > + return mst->tstamp; > > +} > > + > > +noinline uint64_t dt_bvar_ucaller(const dt_dctx_t *dctx) > > +{ > > + uint64_t buf[2] = { 0, }; > > + > > + if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), BPF_F_USER_STACK) < 0) > > + return 0; > > + > > + return buf[1]; > > +} > > + > > +noinline uint64_t dt_bvar_uid(const dt_dctx_t *dctx) > > +{ > > + return bpf_get_current_uid_gid() & 0x00000000ffffffffUL; > > +} > > + > > +noinline uint64_t dt_bvar_ustackdepth(const dt_dctx_t *dctx) > > +{ > > + uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); > > + char *buf = dctx->mem + (uint64_t)(&STACK_OFF); > > + uint64_t retv; > > + > > + retv = bpf_get_stack(dctx->ctx, buf, bufsiz, BPF_F_USER_STACK); > > + if (retv < 0) > > + return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); > > + > > + /* See dt_bvar_stackdepth() above. */ > > + return retv / sizeof(uint64_t); > > +} > > + > > +noinline uint64_t dt_bvar_walltimestamp(const dt_dctx_t *dctx) > > +{ > > + return bpf_ktime_get_ns() + ((uint64_t)&BOOTTM); > > +} > > diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h > > index c8c1d961..9f6e3b55 100644 > > --- a/include/dtrace/dif_defines.h > > +++ b/include/dtrace/dif_defines.h > > @@ -162,6 +162,7 @@ > > #define DIF_VAR_GID 0x011f > > #define DIF_VAR_ERRNO 0x0120 > > #define DIF_VAR_CURCPU 0x0121 > > +#define DIF_VAR_EXECARGS 0x0122 > > #define DIF_SUBR_RAND 0 > > #define DIF_SUBR_MUTEX_OWNED 1 > > diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c > > index e7e3a132..6e74b4b0 100644 > > --- a/libdtrace/dt_cg.c > > +++ b/libdtrace/dt_cg.c > > @@ -3197,6 +3197,7 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > { > > dt_ident_t *idp = dt_ident_resolve(dnp->dn_ident); > > dt_ident_t *fnp; > > + uint32_t idx = UINT32_MAX; > > idp->di_flags |= DT_IDFLG_DIFR; > > @@ -3298,15 +3299,38 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > return; > > } > > - /* built-in variables */ > > + /* built-in variables (note: args[] is handled in dt_cg_array_op) */ > > + /* Special case for arg0 through arg9; encode as args[n] */ > > + if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { > > + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); > > + idx = idp->di_id - DIF_VAR_ARG0; > > + } else if (idp->di_id == DIF_VAR_PROBEPROV || > > + idp->di_id == DIF_VAR_PROBEMOD || > > + idp->di_id == DIF_VAR_PROBEFUNC || > > + idp->di_id == DIF_VAR_PROBENAME) { > > + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_probedesc"); > > + idx = idp->di_id; > > + } else { > > + char *fn; > > + > > + if (asprintf(&fn, "dt_bvar_%s", idp->di_name) == -1) > > + longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); > > + > > + fnp = dt_dlib_get_func(yypcb->pcb_hdl, fn); > > + free(fn); > > + } > > + > > + /* No implementing function found - report ILLOP. */ > > + if (fnp == NULL) > > + xyerror(D_IDENT_UNDEF, > > + "built-in variable '%s' not implemented", idp->di_name); > > + > > if (dt_regset_xalloc_args(drp) == -1) > > longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); > > dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1); > > - emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id)); > > - emit(dlp, BPF_MOV_IMM(BPF_REG_3, 0)); > > - fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar"); > > - assert(fnp != NULL); > > + if (idx != UINT32_MAX) > > + emit(dlp, BPF_MOV_IMM(BPF_REG_2, idx)); > > dt_regset_xalloc(drp, BPF_REG_0); > > emite(dlp, BPF_CALL_FUNC(fnp->di_id), fnp); > > dt_regset_free_args(drp); > > @@ -5065,7 +5089,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > dt_probe_t *prp = yypcb->pcb_probe; > > uintmax_t saved = dnp->dn_args->dn_value; > > dt_ident_t *idp = dnp->dn_ident; > > - dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar"); > > + dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); > > size_t size; > > int n; > > int ustr = 0; > > @@ -5135,8 +5159,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > if (dt_regset_xalloc_args(drp) == -1) > > longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); > > dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1); > > - emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id)); > > - emit(dlp, BPF_MOV_REG(BPF_REG_3, dnp->dn_reg)); > > + emit(dlp, BPF_MOV_REG(BPF_REG_2, dnp->dn_reg)); > > dt_regset_xalloc(drp, BPF_REG_0); > > emite(dlp, BPF_CALL_FUNC(fidp->di_id), fidp); > > dt_regset_free_args(drp); > > diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c > > index 9f319d70..d983c099 100644 > > --- a/libdtrace/dt_dis.c > > +++ b/libdtrace/dt_dis.c > > @@ -364,16 +364,57 @@ static char * > > dt_dis_bpf_args(const dtrace_difo_t *dp, const char *fn, > > const struct bpf_insn *in, char *buf, size_t len, uint_t addr) > > { > > - if (strcmp(fn, "dt_get_bvar") == 0) { > > + if (strcmp(fn, "dt_bvar_args") == 0) { > > /* > > - * We know that the previous two instructions exist and move > > - * the variable id to a register in the first instruction of > > - * that sequence (because we wrote the code generator to emit > > - * the instructions in this exact order.) > > + * We need to support two cases: > > + * - access to argN: > > + * lddw %r1, dctx > > + * mov %r2, N > > + * call dt_bvar_args > > + * - access to args[N]: > > + * mov %rX, N > > + * lddw %r1, dctx > > + * mov %r2, %rX > > + * call dt_bvar_args > > */ > > - in -= 2; > > - snprintf(buf, len, "%s", > > - dt_dis_varname_id(dp, in->imm, DIFV_SCOPE_GLOBAL, addr)); > > + in--; > > + if (BPF_OP(in->code) == BPF_MOV && in->dst_reg == 2) { > > + if (BPF_SRC(in->code) == BPF_K) { > > + snprintf(buf, len, "arg%d", in->imm); > > + return buf; > > + } > > + > > + in -= 2; > > + if (BPF_OP(in->code) == BPF_MOV && > > + BPF_SRC(in->code) == BPF_K && > > + in->dst_reg == in[2].src_reg) { > > + snprintf(buf, len, "args[%d]", in->imm); > > + return buf; > > + } > > + } > > + > > + snprintf(buf, len, "args[?]"); > > + return buf; > > + } else if (strcmp(fn, "dt_bvar_probedesc") == 0) { > > + /* > > + * Access to probe(prov|mod|func|name); > > + * lddw %r1, dctx > > + * mov %r2, N > > + * call dt_bvar_probedesc > > + */ > > + in--; > > + if (BPF_OP(in->code) == BPF_MOV && in->dst_reg == 2 && > > + BPF_SRC(in->code) == BPF_K) { > > + snprintf(buf, len, "%s", > > + dt_dis_varname_id(dp, in->imm, > > + DIFV_SCOPE_GLOBAL, addr)); > > + return buf; > > + } > > + > > + return NULL; > > + } else if (strncmp(fn, "dt_bvar_", 8) == 0) { > > + /* The variable name is in the function name.*/ > > + snprintf(buf, len, "%s", fn + 8); > > return buf; > > } else if (strcmp(fn, "dt_get_agg") == 0) { > > /* > > diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c > > index a0205887..51c056b2 100644 > > --- a/libdtrace/dt_open.c > > +++ b/libdtrace/dt_open.c > > @@ -153,6 +153,8 @@ static const dt_ident_t _dtrace_globals[] = { > > &dt_idops_type, "uint64_t" }, > > { "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0, > > &dt_idops_type, "int" }, > > +{ "execargs", DT_IDENT_SCALAR, 0, DIF_VAR_EXECARGS, > > + DT_ATTR_STABCMN, DT_VERS_2_0, &dt_idops_type, "string" }, > > { "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME, > > DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, > > { "exit", DT_IDENT_ACTFUNC, 0, DT_ACT_EXIT, DT_ATTR_STABCMN, DT_VERS_1_0, > > diff --git a/test/demo/builtin/ipl.d b/test/demo/builtin/ipl.d > > index ca7f3bb7..f613bb70 100644 > > --- a/test/demo/builtin/ipl.d > > +++ b/test/demo/builtin/ipl.d > > @@ -1,3 +1,5 @@ > > +/* @@xfail: dtv2: need ipl support */ > > + > > BEGIN { > > trace(ipl); > > exit(0); > > diff --git a/test/demo/builtin/vtimestamp.d b/test/demo/builtin/vtimestamp.d > > index 9f01bbf0..fcb708d0 100644 > > --- a/test/demo/builtin/vtimestamp.d > > +++ b/test/demo/builtin/vtimestamp.d > > @@ -1,3 +1,5 @@ > > +/* @@xfail: dtv2: need vtimestamp support */ > > + > > BEGIN { > > trace(vtimestamp); > > exit(0); > > diff --git a/test/demo/io/iocpu.d b/test/demo/io/iocpu.d > > index c7b847e7..1230d6f6 100644 > > --- a/test/demo/io/iocpu.d > > +++ b/test/demo/io/iocpu.d > > @@ -5,6 +5,8 @@ > > * http://oss.oracle.com/licenses/upl. > > */ > > +/* @@xfail: dtv2: need vtimestamp support */ > > + > > #pragma D option quiet > > sched:::on-cpu > > diff --git a/test/unittest/buffering/tst.cputime.sh b/test/unittest/buffering/tst.cputime.sh > > index 6a420e8d..c0e248a6 100755 > > --- a/test/unittest/buffering/tst.cputime.sh > > +++ b/test/unittest/buffering/tst.cputime.sh > > @@ -5,6 +5,7 @@ > > # Licensed under the Universal Permissive License v 1.0 as shown at > > # http://oss.oracle.com/licenses/upl. > > # > > +# @@xfail: dtv2: need vtimestamp support > > # @@timeout: 12 > > script() > > diff --git a/test/unittest/disasm/tst.ann-bvar.r b/test/unittest/disasm/tst.ann-bvar.r > > index b514dd99..a55fb6de 100644 > > --- a/test/unittest/disasm/tst.ann-bvar.r > > +++ b/test/unittest/disasm/tst.ann-bvar.r > > @@ -1,34 +1,35 @@ > > -85 0 1 0000 ffffffff call dt_get_bvar ! arg0 > > -85 0 1 0000 ffffffff call dt_get_bvar ! arg1 > > -85 0 1 0000 ffffffff call dt_get_bvar ! arg2 > > -85 0 1 0000 ffffffff call dt_get_bvar ! arg3 > > -85 0 1 0000 ffffffff call dt_get_bvar ! arg4 > > -85 0 1 0000 ffffffff call dt_get_bvar ! arg5 > > -85 0 1 0000 ffffffff call dt_get_bvar ! arg6 > > -85 0 1 0000 ffffffff call dt_get_bvar ! arg7 > > -85 0 1 0000 ffffffff call dt_get_bvar ! arg8 > > -85 0 1 0000 ffffffff call dt_get_bvar ! arg9 > > -85 0 1 0000 ffffffff call dt_get_bvar ! args > > -85 0 1 0000 ffffffff call dt_get_bvar ! caller > > -85 0 1 0000 ffffffff call dt_get_bvar ! curcpu > > -85 0 1 0000 ffffffff call dt_get_bvar ! curthread > > -85 0 1 0000 ffffffff call dt_get_bvar ! epid > > -85 0 1 0000 ffffffff call dt_get_bvar ! errno > > -85 0 1 0000 ffffffff call dt_get_bvar ! execname > > -85 0 1 0000 ffffffff call dt_get_bvar ! gid > > -85 0 1 0000 ffffffff call dt_get_bvar ! id > > -85 0 1 0000 ffffffff call dt_get_bvar ! ipl > > -85 0 1 0000 ffffffff call dt_get_bvar ! pid > > -85 0 1 0000 ffffffff call dt_get_bvar ! ppid > > -85 0 1 0000 ffffffff call dt_get_bvar ! probefunc > > -85 0 1 0000 ffffffff call dt_get_bvar ! probemod > > -85 0 1 0000 ffffffff call dt_get_bvar ! probename > > -85 0 1 0000 ffffffff call dt_get_bvar ! probeprov > > -85 0 1 0000 ffffffff call dt_get_bvar ! stackdepth > > -85 0 1 0000 ffffffff call dt_get_bvar ! tid > > -85 0 1 0000 ffffffff call dt_get_bvar ! timestamp > > -85 0 1 0000 ffffffff call dt_get_bvar ! ucaller > > -85 0 1 0000 ffffffff call dt_get_bvar ! uid > > -85 0 1 0000 ffffffff call dt_get_bvar ! ustackdepth > > -85 0 1 0000 ffffffff call dt_get_bvar ! vtimestamp > > -85 0 1 0000 ffffffff call dt_get_bvar ! walltimestamp > > +85 0 1 0000 ffffffff call dt_bvar_args ! arg0 > > +85 0 1 0000 ffffffff call dt_bvar_args ! arg1 > > +85 0 1 0000 ffffffff call dt_bvar_args ! arg2 > > +85 0 1 0000 ffffffff call dt_bvar_args ! arg3 > > +85 0 1 0000 ffffffff call dt_bvar_args ! arg4 > > +85 0 1 0000 ffffffff call dt_bvar_args ! arg5 > > +85 0 1 0000 ffffffff call dt_bvar_args ! arg6 > > +85 0 1 0000 ffffffff call dt_bvar_args ! arg7 > > +85 0 1 0000 ffffffff call dt_bvar_args ! arg8 > > +85 0 1 0000 ffffffff call dt_bvar_args ! arg9 > > +85 0 1 0000 ffffffff call dt_bvar_args ! args[0] > > +85 0 1 0000 ffffffff call dt_bvar_args ! args[1] > > +85 0 1 0000 ffffffff call dt_bvar_args ! args[2] > > +85 0 1 0000 ffffffff call dt_bvar_args ! args[3] > > +85 0 1 0000 ffffffff call dt_bvar_caller ! caller > > +85 0 1 0000 ffffffff call dt_bvar_curcpu ! curcpu > > +85 0 1 0000 ffffffff call dt_bvar_curthread ! curthread > > +85 0 1 0000 ffffffff call dt_bvar_epid ! epid > > +85 0 1 0000 ffffffff call dt_bvar_errno ! errno > > +85 0 1 0000 ffffffff call dt_bvar_execname ! execname > > +85 0 1 0000 ffffffff call dt_bvar_gid ! gid > > +85 0 1 0000 ffffffff call dt_bvar_id ! id > > +85 0 1 0000 ffffffff call dt_bvar_pid ! pid > > +85 0 1 0000 ffffffff call dt_bvar_ppid ! ppid > > +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probefunc > > +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probemod > > +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probename > > +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probeprov > > +85 0 1 0000 ffffffff call dt_bvar_stackdepth ! stackdepth > > +85 0 1 0000 ffffffff call dt_bvar_tid ! tid > > +85 0 1 0000 ffffffff call dt_bvar_timestamp ! timestamp > > +85 0 1 0000 ffffffff call dt_bvar_ucaller ! ucaller > > +85 0 1 0000 ffffffff call dt_bvar_uid ! uid > > +85 0 1 0000 ffffffff call dt_bvar_ustackdepth ! ustackdepth > > +85 0 1 0000 ffffffff call dt_bvar_walltimestamp ! walltimestamp > > diff --git a/test/unittest/disasm/tst.ann-bvar.sh b/test/unittest/disasm/tst.ann-bvar.sh > > index 6dc43424..61e838d1 100755 > > --- a/test/unittest/disasm/tst.ann-bvar.sh > > +++ b/test/unittest/disasm/tst.ann-bvar.sh > > @@ -22,6 +22,9 @@ sdt:task::task_rename > > trace(arg8); > > trace(arg9); > > trace(args[0]); > > + trace(args[1]); > > + trace(args[2]); > > + trace(args[3]); > > trace(caller); > > trace(curcpu); > > trace(curthread); > > @@ -30,7 +33,7 @@ sdt:task::task_rename > > trace(execname); > > trace(gid); > > trace(id); > > - trace(ipl); > > +/* trace(ipl); */ > > trace(pid); > > trace(ppid); > > trace(probefunc); > > @@ -43,10 +46,10 @@ sdt:task::task_rename > > trace(ucaller); > > trace(uid); > > trace(ustackdepth); > > - trace(vtimestamp); > > +/* trace(vtimestamp); */ > > trace(walltimestamp); > > exit(0); > > } > > -' 2>&1 | gawk '/ call dt_get_bvar/ { sub(/^[^:]+: /, ""); print; }' > > +' 2>&1 | gawk '/ call dt_bvar_/ { sub(/^[^:]+: /, ""); print; }' > > exit $? > > diff --git a/test/unittest/disasm/tst.vartab-bvar.r b/test/unittest/disasm/tst.vartab-bvar.r > > index 53e5f618..04fa3a8d 100644 > > --- a/test/unittest/disasm/tst.vartab-bvar.r > > +++ b/test/unittest/disasm/tst.vartab-bvar.r > > @@ -2,8 +2,6 @@ NAME OFFSET KND SCP FLAG TYPE > > args arr glb r any (unknown) by ref (size 0) > > 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 8) > > id scl glb r D type (integer) (size 4) > > arg0 scl glb r D type (integer) (size 8) > > diff --git a/test/unittest/disasm/tst.vartab-bvar.sh b/test/unittest/disasm/tst.vartab-bvar.sh > > index 098c1f45..ce489a24 100755 > > --- a/test/unittest/disasm/tst.vartab-bvar.sh > > +++ b/test/unittest/disasm/tst.vartab-bvar.sh > > @@ -30,6 +30,9 @@ sdt:task::task_rename > > trace(arg8); > > trace(arg9); > > trace(args[0]); > > + trace(args[1]); > > + trace(args[2]); > > + trace(args[3]); > > trace(caller); > > trace(curcpu); > > trace(curthread); > > @@ -38,7 +41,7 @@ sdt:task::task_rename > > trace(execname); > > trace(gid); > > trace(id); > > - trace(ipl); > > +/* trace(ipl); */ > > trace(pid); > > trace(ppid); > > trace(probefunc); > > @@ -52,7 +55,7 @@ sdt:task::task_rename > > trace(uid); > > /* trace(uregs[0]); */ /* test this separately until uregs[0] works on all kernels */ > > trace(ustackdepth); > > - trace(vtimestamp); > > +/* trace(vtimestamp); */ > > trace(walltimestamp); > > exit(0); > > } From kris.van.hees at oracle.com Tue Jan 28 06:31:40 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 28 Jan 2025 01:31:40 -0500 Subject: [DTrace-devel] [PATCH v2 1/6] bpf: separate bvar implementation into separate functions Message-ID: The handling of builtin variables was done with a single big function that therefore got linked into every single BPF program (twice if the builtin variable might raise a fault). Providing separate functions for most builtin variables reduces BPF program size significantly. This also reduces pressure on the BPF verifies. Signed-off-by: Kris Van Hees --- bpf/get_bvar.c | 412 +++++++++++++----------- libdtrace/dt_cg.c | 39 ++- libdtrace/dt_dis.c | 57 +++- test/demo/builtin/ipl.d | 2 + test/demo/builtin/vtimestamp.d | 2 + test/demo/io/iocpu.d | 2 + test/unittest/buffering/tst.cputime.sh | 1 + test/unittest/disasm/tst.ann-bvar.r | 69 ++-- test/unittest/disasm/tst.ann-bvar.sh | 9 +- test/unittest/disasm/tst.vartab-bvar.r | 2 - test/unittest/disasm/tst.vartab-bvar.sh | 7 +- 11 files changed, 357 insertions(+), 245 deletions(-) diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c index 1c0fa884..c760126d 100644 --- a/bpf/get_bvar.c +++ b/bpf/get_bvar.c @@ -19,18 +19,21 @@ # define noinline __attribute__((noinline)) #endif -extern struct bpf_map_def cpuinfo; -extern struct bpf_map_def probes; -extern struct bpf_map_def state; -extern struct bpf_map_def usdt_names; - -extern uint64_t PC; -extern uint64_t STBSZ; -extern uint64_t STKSIZ; -extern uint64_t BOOTTM; +extern struct bpf_map_def cpuinfo; +extern struct bpf_map_def probes; +extern struct bpf_map_def state; +extern struct bpf_map_def usdt_names; + +extern uint64_t BOOTTM; +extern uint64_t NPROBES; +extern uint64_t PC; +extern uint64_t STBSZ; +extern uint64_t STKSIZ; extern uint64_t STACK_OFF; -extern uint64_t STACK_SKIP; -extern uint64_t NPROBES; +extern uint64_t STACK_SKIP; +extern uint64_t TASK_COMM; +extern uint64_t TASK_REAL_PARENT; +extern uint64_t TASK_TGID; #define error(dctx, fault, illval) \ ({ \ @@ -38,198 +41,231 @@ extern uint64_t NPROBES; -1; \ }) -noinline uint64_t dt_get_bvar(const dt_dctx_t *dctx, uint32_t id, uint32_t idx) +noinline uint64_t dt_bvar_args(const dt_dctx_t *dctx, uint32_t idx) { dt_mstate_t *mst = dctx->mst; - switch (id) { - case DIF_VAR_CURTHREAD: - return bpf_get_current_task(); - case DIF_VAR_TIMESTAMP: - if (mst->tstamp == 0) - mst->tstamp = bpf_ktime_get_ns(); + if (idx >= sizeof(mst->argv) / sizeof(mst->argv[0])) + return error(dctx, DTRACEFLT_ILLOP, 0); - return mst->tstamp; - case DIF_VAR_EPID: { - return (((uint64_t)mst->prid) << 32) | mst->stid; - } - case DIF_VAR_ID: - return mst->prid; - case DIF_VAR_ARG0: case DIF_VAR_ARG1: case DIF_VAR_ARG2: - case DIF_VAR_ARG3: case DIF_VAR_ARG4: case DIF_VAR_ARG5: - case DIF_VAR_ARG6: case DIF_VAR_ARG7: case DIF_VAR_ARG8: - case DIF_VAR_ARG9: - return mst->argv[id - DIF_VAR_ARG0]; - case DIF_VAR_ARGS: - if (idx >= sizeof(mst->argv) / sizeof(mst->argv[0])) - return error(dctx, DTRACEFLT_ILLOP, 0); - - return mst->argv[idx]; - case DIF_VAR_STACKDEPTH: - case DIF_VAR_USTACKDEPTH: { - uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); - uint64_t flags; - char *buf = dctx->mem + (uint64_t)(&STACK_OFF); - uint64_t stacksize; - - if (id == DIF_VAR_USTACKDEPTH) - flags = BPF_F_USER_STACK; - else - flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK; - - stacksize = bpf_get_stack(dctx->ctx, buf, bufsiz, flags); - if (stacksize < 0) - return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); + return mst->argv[idx]; +} + +noinline uint64_t dt_bvar_caller(const dt_dctx_t *dctx) +{ + uint64_t buf[2] = { 0, }; + if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), + (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK) < 0) + return 0; + + return buf[1]; +} + +noinline uint64_t dt_bvar_curcpu(const dt_dctx_t *dctx) +{ + uint32_t key = 0; + void *val = bpf_map_lookup_elem(&cpuinfo, &key); + + if (val == NULL) { /* - * While linux/bpf.h does not describe the meaning of - * bpf_get_stack()'s return value outside of its sign, - * it is presumably the length of the copied stack. - * - * If stacksize==bufsiz, presumably the stack is larger than - * what we can retrieve. But it's also possible that the - * buffer was exactly large enough. So, leave it to the user - * to interpret the result. + * Typically, we would use 'return error(...);' but + * that confuses the verifier because it returns -1. + * So, instead, we explicitly return 0. */ - return stacksize / sizeof(uint64_t); - } - case DIF_VAR_CALLER: - case DIF_VAR_UCALLER: { - uint64_t flags; - uint64_t buf[2] = { 0, }; - - if (id == DIF_VAR_UCALLER) - flags = BPF_F_USER_STACK; - else - flags = (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK; - - if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), flags) < 0) - return 0; - return buf[1]; + error(dctx, DTRACEFLT_ILLOP, 0); + return 0; } - case DIF_VAR_PROBEPROV: - case DIF_VAR_PROBEMOD: - case DIF_VAR_PROBEFUNC: - case DIF_VAR_PROBENAME: { - uint32_t key = mst->prid; - - if (key < ((uint64_t)&NPROBES)) { - dt_bpf_probe_t *pinfo; - uint64_t off; - - pinfo = bpf_map_lookup_elem(&probes, &key); - if (pinfo == NULL) - return (uint64_t)dctx->strtab; - - switch (id) { - case DIF_VAR_PROBEPROV: - off = pinfo->prv; - break; - case DIF_VAR_PROBEMOD: - off = pinfo->mod; - break; - case DIF_VAR_PROBEFUNC: - off = pinfo->fun; - break; - case DIF_VAR_PROBENAME: - off = pinfo->prb; - } - if (off > (uint64_t)&STBSZ) - return (uint64_t)dctx->strtab; - - return (uint64_t)(dctx->strtab + off); - } else { - char *s; - - s = bpf_map_lookup_elem(&usdt_names, &key); - if (s == NULL) - return (uint64_t)dctx->strtab; - - switch (id) { - case DIF_VAR_PROBENAME: - s += DTRACE_FUNCNAMELEN; - case DIF_VAR_PROBEFUNC: - s += DTRACE_MODNAMELEN; - case DIF_VAR_PROBEMOD: - s += DTRACE_PROVNAMELEN; - case DIF_VAR_PROBEPROV: - } - - return (uint64_t)s; - } - } - case DIF_VAR_PID: { - uint64_t val = bpf_get_current_pid_tgid(); - return val >> 32; - } - case DIF_VAR_TID: { - uint64_t val = bpf_get_current_pid_tgid(); + return (uint64_t)val; +} - return val & 0x00000000ffffffffUL; - } - case DIF_VAR_EXECNAME: { - uint64_t ptr; - extern uint64_t TASK_COMM; +noinline uint64_t dt_bvar_curthread(const dt_dctx_t *dctx) +{ + return bpf_get_current_task(); +} - /* &(current->comm) */ - ptr = bpf_get_current_task(); - if (ptr == 0) - return error(dctx, DTRACEFLT_BADADDR, ptr); +noinline uint64_t dt_bvar_epid(const dt_dctx_t *dctx) +{ + dt_mstate_t *mst = dctx->mst; - return (uint64_t)ptr + (uint64_t)&TASK_COMM; - } - case DIF_VAR_WALLTIMESTAMP: - return bpf_ktime_get_ns() + ((uint64_t)&BOOTTM); - case DIF_VAR_PPID: { - uint64_t ptr; - int32_t val = -1; - extern uint64_t TASK_REAL_PARENT; - extern uint64_t TASK_TGID; - - /* Chase pointers val = current->real_parent->tgid. */ - ptr = bpf_get_current_task(); - if (ptr == 0) - return error(dctx, DTRACEFLT_BADADDR, ptr); - if (bpf_probe_read((void *)&ptr, 8, - (const void *)(ptr + (uint64_t)&TASK_REAL_PARENT))) - return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_REAL_PARENT); - if (bpf_probe_read((void *)&val, 4, - (const void *)(ptr + (uint64_t)&TASK_TGID))) - return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_TGID); - - return (uint64_t)val; - } - case DIF_VAR_UID: { - uint64_t val = bpf_get_current_uid_gid(); + return (((uint64_t)mst->prid) << 32) | mst->stid; +} - return val & 0x00000000ffffffffUL; - } - case DIF_VAR_GID: { - uint64_t val = bpf_get_current_uid_gid(); +noinline uint64_t dt_bvar_errno(const dt_dctx_t *dctx) +{ + dt_mstate_t *mst = dctx->mst; - return val >> 32; - } - case DIF_VAR_ERRNO: - return mst->syscall_errno; - case DIF_VAR_CURCPU: { - uint32_t key = 0; - void *val = bpf_map_lookup_elem(&cpuinfo, &key); - - if (val == NULL) { - /* - * Typically, we would use 'return error(...);' but - * that confuses the verifier because it returns -1. - * So, instead, we explicitly return 0. - */ - error(dctx, DTRACEFLT_ILLOP, 0); - return 0; + return mst->syscall_errno; +} + +noinline uint64_t dt_bvar_execname(const dt_dctx_t *dctx) +{ + uint64_t ptr; + + /* &(current->comm) */ + ptr = bpf_get_current_task(); + if (ptr == 0) + return error(dctx, DTRACEFLT_BADADDR, ptr); + + return (uint64_t)ptr + (uint64_t)&TASK_COMM; +} + +noinline uint64_t dt_bvar_gid(const dt_dctx_t *dctx) +{ + return bpf_get_current_uid_gid() >> 32; +} + +noinline uint64_t dt_bvar_id(const dt_dctx_t *dctx) +{ + dt_mstate_t *mst = dctx->mst; + + return mst->prid; +} + +noinline uint64_t dt_bvar_pid(const dt_dctx_t *dctx) +{ + return bpf_get_current_pid_tgid() >> 32; +} + +noinline uint64_t dt_bvar_ppid(const dt_dctx_t *dctx) +{ + uint64_t ptr; + int32_t val = -1; + + /* Chase pointers val = current->real_parent->tgid. */ + ptr = bpf_get_current_task(); + if (ptr == 0) + return error(dctx, DTRACEFLT_BADADDR, ptr); + if (bpf_probe_read((void *)&ptr, 8, + (const void *)(ptr + (uint64_t)&TASK_REAL_PARENT))) + return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_REAL_PARENT); + if (bpf_probe_read((void *)&val, 4, + (const void *)(ptr + (uint64_t)&TASK_TGID))) + return error(dctx, DTRACEFLT_BADADDR, ptr + (uint64_t)&TASK_TGID); + + return (uint64_t)val; +} + +noinline uint64_t dt_bvar_probedesc(const dt_dctx_t *dctx, uint32_t idx) +{ + dt_mstate_t *mst = dctx->mst; + uint32_t key = mst->prid; + + if (key < ((uint64_t)&NPROBES)) { + dt_bpf_probe_t *pinfo; + uint64_t off = 0; + + pinfo = bpf_map_lookup_elem(&probes, &key); + if (pinfo == NULL) + return (uint64_t)dctx->strtab; + + switch (idx) { + case DIF_VAR_PROBEPROV: + off = pinfo->prv; + break; + case DIF_VAR_PROBEMOD: + off = pinfo->mod; + break; + case DIF_VAR_PROBEFUNC: + off = pinfo->fun; + break; + case DIF_VAR_PROBENAME: + off = pinfo->prb; } + if (off > (uint64_t)&STBSZ) + return (uint64_t)dctx->strtab; - return (uint64_t)val; - } - default: - /* Not implemented yet. */ - return error(dctx, DTRACEFLT_ILLOP, 0); + return (uint64_t)(dctx->strtab + off); + } else { + char *s; + + s = bpf_map_lookup_elem(&usdt_names, &key); + if (s == NULL) + return (uint64_t)dctx->strtab; + + switch (idx) { + case DIF_VAR_PROBEPROV: + s += DTRACE_FUNCNAMELEN; + case DIF_VAR_PROBEMOD: + s += DTRACE_MODNAMELEN; + case DIF_VAR_PROBEFUNC: + s += DTRACE_PROVNAMELEN; + case DIF_VAR_PROBENAME: + } + + return (uint64_t)s; } } + +noinline uint64_t dt_bvar_stackdepth(const dt_dctx_t *dctx) +{ + uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); + char *buf = dctx->mem + (uint64_t)(&STACK_OFF); + uint64_t retv; + + retv = bpf_get_stack(dctx->ctx, buf, bufsiz, + (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK); + if (retv < 0) + return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); + + /* + * While linux/bpf.h does not describe the meaning of bpf_get_stack()'s + * return value outside of its sign, it is presumably the length of the + * copied stack. + * + * If retv==bufsiz, presumably the stack is larger than what we + * can retrieve. But it's also possible that the buffer was exactly + * large enough. So, leave it to the user to interpret the result. + */ + return retv / sizeof(uint64_t); +} + +noinline uint64_t dt_bvar_tid(const dt_dctx_t *dctx) +{ + return bpf_get_current_pid_tgid() & 0x00000000ffffffffUL; +} + +noinline uint64_t dt_bvar_timestamp(const dt_dctx_t *dctx) +{ + dt_mstate_t *mst = dctx->mst; + + if (mst->tstamp == 0) + mst->tstamp = bpf_ktime_get_ns(); + + return mst->tstamp; +} + +noinline uint64_t dt_bvar_ucaller(const dt_dctx_t *dctx) +{ + uint64_t buf[2] = { 0, }; + + if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), BPF_F_USER_STACK) < 0) + return 0; + + return buf[1]; +} + +noinline uint64_t dt_bvar_uid(const dt_dctx_t *dctx) +{ + return bpf_get_current_uid_gid() & 0x00000000ffffffffUL; +} + +noinline uint64_t dt_bvar_ustackdepth(const dt_dctx_t *dctx) +{ + uint32_t bufsiz = (uint32_t) (uint64_t) (&STKSIZ); + char *buf = dctx->mem + (uint64_t)(&STACK_OFF); + uint64_t retv; + + retv = bpf_get_stack(dctx->ctx, buf, bufsiz, BPF_F_USER_STACK); + if (retv < 0) + return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); + + /* See dt_bvar_stackdepth() above. */ + return retv / sizeof(uint64_t); +} + +noinline uint64_t dt_bvar_walltimestamp(const dt_dctx_t *dctx) +{ + return bpf_ktime_get_ns() + ((uint64_t)&BOOTTM); +} diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index e7e3a132..6e74b4b0 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -3197,6 +3197,7 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) { dt_ident_t *idp = dt_ident_resolve(dnp->dn_ident); dt_ident_t *fnp; + uint32_t idx = UINT32_MAX; idp->di_flags |= DT_IDFLG_DIFR; @@ -3298,15 +3299,38 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) return; } - /* built-in variables */ + /* built-in variables (note: args[] is handled in dt_cg_array_op) */ + /* Special case for arg0 through arg9; encode as args[n] */ + if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); + idx = idp->di_id - DIF_VAR_ARG0; + } else if (idp->di_id == DIF_VAR_PROBEPROV || + idp->di_id == DIF_VAR_PROBEMOD || + idp->di_id == DIF_VAR_PROBEFUNC || + idp->di_id == DIF_VAR_PROBENAME) { + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_probedesc"); + idx = idp->di_id; + } else { + char *fn; + + if (asprintf(&fn, "dt_bvar_%s", idp->di_name) == -1) + longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); + + fnp = dt_dlib_get_func(yypcb->pcb_hdl, fn); + free(fn); + } + + /* No implementing function found - report ILLOP. */ + if (fnp == NULL) + xyerror(D_IDENT_UNDEF, + "built-in variable '%s' not implemented", idp->di_name); + if (dt_regset_xalloc_args(drp) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1); - emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id)); - emit(dlp, BPF_MOV_IMM(BPF_REG_3, 0)); - fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar"); - assert(fnp != NULL); + if (idx != UINT32_MAX) + emit(dlp, BPF_MOV_IMM(BPF_REG_2, idx)); dt_regset_xalloc(drp, BPF_REG_0); emite(dlp, BPF_CALL_FUNC(fnp->di_id), fnp); dt_regset_free_args(drp); @@ -5065,7 +5089,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) dt_probe_t *prp = yypcb->pcb_probe; uintmax_t saved = dnp->dn_args->dn_value; dt_ident_t *idp = dnp->dn_ident; - dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar"); + dt_ident_t *fidp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); size_t size; int n; int ustr = 0; @@ -5135,8 +5159,7 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) if (dt_regset_xalloc_args(drp) == -1) longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1); - emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id)); - emit(dlp, BPF_MOV_REG(BPF_REG_3, dnp->dn_reg)); + emit(dlp, BPF_MOV_REG(BPF_REG_2, dnp->dn_reg)); dt_regset_xalloc(drp, BPF_REG_0); emite(dlp, BPF_CALL_FUNC(fidp->di_id), fidp); dt_regset_free_args(drp); diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c index 9f319d70..d983c099 100644 --- a/libdtrace/dt_dis.c +++ b/libdtrace/dt_dis.c @@ -364,16 +364,57 @@ static char * dt_dis_bpf_args(const dtrace_difo_t *dp, const char *fn, const struct bpf_insn *in, char *buf, size_t len, uint_t addr) { - if (strcmp(fn, "dt_get_bvar") == 0) { + if (strcmp(fn, "dt_bvar_args") == 0) { /* - * We know that the previous two instructions exist and move - * the variable id to a register in the first instruction of - * that sequence (because we wrote the code generator to emit - * the instructions in this exact order.) + * We need to support two cases: + * - access to argN: + * lddw %r1, dctx + * mov %r2, N + * call dt_bvar_args + * - access to args[N]: + * mov %rX, N + * lddw %r1, dctx + * mov %r2, %rX + * call dt_bvar_args */ - in -= 2; - snprintf(buf, len, "%s", - dt_dis_varname_id(dp, in->imm, DIFV_SCOPE_GLOBAL, addr)); + in--; + if (BPF_OP(in->code) == BPF_MOV && in->dst_reg == 2) { + if (BPF_SRC(in->code) == BPF_K) { + snprintf(buf, len, "arg%d", in->imm); + return buf; + } + + in -= 2; + if (BPF_OP(in->code) == BPF_MOV && + BPF_SRC(in->code) == BPF_K && + in->dst_reg == in[2].src_reg) { + snprintf(buf, len, "args[%d]", in->imm); + return buf; + } + } + + snprintf(buf, len, "args[?]"); + return buf; + } else if (strcmp(fn, "dt_bvar_probedesc") == 0) { + /* + * Access to probe(prov|mod|func|name); + * lddw %r1, dctx + * mov %r2, N + * call dt_bvar_probedesc + */ + in--; + if (BPF_OP(in->code) == BPF_MOV && in->dst_reg == 2 && + BPF_SRC(in->code) == BPF_K) { + snprintf(buf, len, "%s", + dt_dis_varname_id(dp, in->imm, + DIFV_SCOPE_GLOBAL, addr)); + return buf; + } + + return NULL; + } else if (strncmp(fn, "dt_bvar_", 8) == 0) { + /* The variable name is in the function name.*/ + snprintf(buf, len, "%s", fn + 8); return buf; } else if (strcmp(fn, "dt_get_agg") == 0) { /* diff --git a/test/demo/builtin/ipl.d b/test/demo/builtin/ipl.d index ca7f3bb7..f613bb70 100644 --- a/test/demo/builtin/ipl.d +++ b/test/demo/builtin/ipl.d @@ -1,3 +1,5 @@ +/* @@xfail: dtv2: need ipl support */ + BEGIN { trace(ipl); exit(0); diff --git a/test/demo/builtin/vtimestamp.d b/test/demo/builtin/vtimestamp.d index 9f01bbf0..fcb708d0 100644 --- a/test/demo/builtin/vtimestamp.d +++ b/test/demo/builtin/vtimestamp.d @@ -1,3 +1,5 @@ +/* @@xfail: dtv2: need vtimestamp support */ + BEGIN { trace(vtimestamp); exit(0); diff --git a/test/demo/io/iocpu.d b/test/demo/io/iocpu.d index c7b847e7..1230d6f6 100644 --- a/test/demo/io/iocpu.d +++ b/test/demo/io/iocpu.d @@ -5,6 +5,8 @@ * http://oss.oracle.com/licenses/upl. */ +/* @@xfail: dtv2: need vtimestamp support */ + #pragma D option quiet sched:::on-cpu diff --git a/test/unittest/buffering/tst.cputime.sh b/test/unittest/buffering/tst.cputime.sh index 6a420e8d..c0e248a6 100755 --- a/test/unittest/buffering/tst.cputime.sh +++ b/test/unittest/buffering/tst.cputime.sh @@ -5,6 +5,7 @@ # Licensed under the Universal Permissive License v 1.0 as shown at # http://oss.oracle.com/licenses/upl. # +# @@xfail: dtv2: need vtimestamp support # @@timeout: 12 script() diff --git a/test/unittest/disasm/tst.ann-bvar.r b/test/unittest/disasm/tst.ann-bvar.r index b514dd99..a55fb6de 100644 --- a/test/unittest/disasm/tst.ann-bvar.r +++ b/test/unittest/disasm/tst.ann-bvar.r @@ -1,34 +1,35 @@ -85 0 1 0000 ffffffff call dt_get_bvar ! arg0 -85 0 1 0000 ffffffff call dt_get_bvar ! arg1 -85 0 1 0000 ffffffff call dt_get_bvar ! arg2 -85 0 1 0000 ffffffff call dt_get_bvar ! arg3 -85 0 1 0000 ffffffff call dt_get_bvar ! arg4 -85 0 1 0000 ffffffff call dt_get_bvar ! arg5 -85 0 1 0000 ffffffff call dt_get_bvar ! arg6 -85 0 1 0000 ffffffff call dt_get_bvar ! arg7 -85 0 1 0000 ffffffff call dt_get_bvar ! arg8 -85 0 1 0000 ffffffff call dt_get_bvar ! arg9 -85 0 1 0000 ffffffff call dt_get_bvar ! args -85 0 1 0000 ffffffff call dt_get_bvar ! caller -85 0 1 0000 ffffffff call dt_get_bvar ! curcpu -85 0 1 0000 ffffffff call dt_get_bvar ! curthread -85 0 1 0000 ffffffff call dt_get_bvar ! epid -85 0 1 0000 ffffffff call dt_get_bvar ! errno -85 0 1 0000 ffffffff call dt_get_bvar ! execname -85 0 1 0000 ffffffff call dt_get_bvar ! gid -85 0 1 0000 ffffffff call dt_get_bvar ! id -85 0 1 0000 ffffffff call dt_get_bvar ! ipl -85 0 1 0000 ffffffff call dt_get_bvar ! pid -85 0 1 0000 ffffffff call dt_get_bvar ! ppid -85 0 1 0000 ffffffff call dt_get_bvar ! probefunc -85 0 1 0000 ffffffff call dt_get_bvar ! probemod -85 0 1 0000 ffffffff call dt_get_bvar ! probename -85 0 1 0000 ffffffff call dt_get_bvar ! probeprov -85 0 1 0000 ffffffff call dt_get_bvar ! stackdepth -85 0 1 0000 ffffffff call dt_get_bvar ! tid -85 0 1 0000 ffffffff call dt_get_bvar ! timestamp -85 0 1 0000 ffffffff call dt_get_bvar ! ucaller -85 0 1 0000 ffffffff call dt_get_bvar ! uid -85 0 1 0000 ffffffff call dt_get_bvar ! ustackdepth -85 0 1 0000 ffffffff call dt_get_bvar ! vtimestamp -85 0 1 0000 ffffffff call dt_get_bvar ! walltimestamp +85 0 1 0000 ffffffff call dt_bvar_args ! arg0 +85 0 1 0000 ffffffff call dt_bvar_args ! arg1 +85 0 1 0000 ffffffff call dt_bvar_args ! arg2 +85 0 1 0000 ffffffff call dt_bvar_args ! arg3 +85 0 1 0000 ffffffff call dt_bvar_args ! arg4 +85 0 1 0000 ffffffff call dt_bvar_args ! arg5 +85 0 1 0000 ffffffff call dt_bvar_args ! arg6 +85 0 1 0000 ffffffff call dt_bvar_args ! arg7 +85 0 1 0000 ffffffff call dt_bvar_args ! arg8 +85 0 1 0000 ffffffff call dt_bvar_args ! arg9 +85 0 1 0000 ffffffff call dt_bvar_args ! args[0] +85 0 1 0000 ffffffff call dt_bvar_args ! args[1] +85 0 1 0000 ffffffff call dt_bvar_args ! args[2] +85 0 1 0000 ffffffff call dt_bvar_args ! args[3] +85 0 1 0000 ffffffff call dt_bvar_caller ! caller +85 0 1 0000 ffffffff call dt_bvar_curcpu ! curcpu +85 0 1 0000 ffffffff call dt_bvar_curthread ! curthread +85 0 1 0000 ffffffff call dt_bvar_epid ! epid +85 0 1 0000 ffffffff call dt_bvar_errno ! errno +85 0 1 0000 ffffffff call dt_bvar_execname ! execname +85 0 1 0000 ffffffff call dt_bvar_gid ! gid +85 0 1 0000 ffffffff call dt_bvar_id ! id +85 0 1 0000 ffffffff call dt_bvar_pid ! pid +85 0 1 0000 ffffffff call dt_bvar_ppid ! ppid +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probefunc +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probemod +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probename +85 0 1 0000 ffffffff call dt_bvar_probedesc ! probeprov +85 0 1 0000 ffffffff call dt_bvar_stackdepth ! stackdepth +85 0 1 0000 ffffffff call dt_bvar_tid ! tid +85 0 1 0000 ffffffff call dt_bvar_timestamp ! timestamp +85 0 1 0000 ffffffff call dt_bvar_ucaller ! ucaller +85 0 1 0000 ffffffff call dt_bvar_uid ! uid +85 0 1 0000 ffffffff call dt_bvar_ustackdepth ! ustackdepth +85 0 1 0000 ffffffff call dt_bvar_walltimestamp ! walltimestamp diff --git a/test/unittest/disasm/tst.ann-bvar.sh b/test/unittest/disasm/tst.ann-bvar.sh index 6dc43424..61e838d1 100755 --- a/test/unittest/disasm/tst.ann-bvar.sh +++ b/test/unittest/disasm/tst.ann-bvar.sh @@ -22,6 +22,9 @@ sdt:task::task_rename trace(arg8); trace(arg9); trace(args[0]); + trace(args[1]); + trace(args[2]); + trace(args[3]); trace(caller); trace(curcpu); trace(curthread); @@ -30,7 +33,7 @@ sdt:task::task_rename trace(execname); trace(gid); trace(id); - trace(ipl); +/* trace(ipl); */ trace(pid); trace(ppid); trace(probefunc); @@ -43,10 +46,10 @@ sdt:task::task_rename trace(ucaller); trace(uid); trace(ustackdepth); - trace(vtimestamp); +/* trace(vtimestamp); */ trace(walltimestamp); exit(0); } -' 2>&1 | gawk '/ call dt_get_bvar/ { sub(/^[^:]+: /, ""); print; }' +' 2>&1 | gawk '/ call dt_bvar_/ { sub(/^[^:]+: /, ""); print; }' exit $? diff --git a/test/unittest/disasm/tst.vartab-bvar.r b/test/unittest/disasm/tst.vartab-bvar.r index 53e5f618..04fa3a8d 100644 --- a/test/unittest/disasm/tst.vartab-bvar.r +++ b/test/unittest/disasm/tst.vartab-bvar.r @@ -2,8 +2,6 @@ NAME OFFSET KND SCP FLAG TYPE args arr glb r any (unknown) by ref (size 0) 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 8) id scl glb r D type (integer) (size 4) arg0 scl glb r D type (integer) (size 8) diff --git a/test/unittest/disasm/tst.vartab-bvar.sh b/test/unittest/disasm/tst.vartab-bvar.sh index 098c1f45..ce489a24 100755 --- a/test/unittest/disasm/tst.vartab-bvar.sh +++ b/test/unittest/disasm/tst.vartab-bvar.sh @@ -30,6 +30,9 @@ sdt:task::task_rename trace(arg8); trace(arg9); trace(args[0]); + trace(args[1]); + trace(args[2]); + trace(args[3]); trace(caller); trace(curcpu); trace(curthread); @@ -38,7 +41,7 @@ sdt:task::task_rename trace(execname); trace(gid); trace(id); - trace(ipl); +/* trace(ipl); */ trace(pid); trace(ppid); trace(probefunc); @@ -52,7 +55,7 @@ sdt:task::task_rename trace(uid); /* trace(uregs[0]); */ /* test this separately until uregs[0] works on all kernels */ trace(ustackdepth); - trace(vtimestamp); +/* trace(vtimestamp); */ trace(walltimestamp); exit(0); } -- 2.45.2 From kris.van.hees at oracle.com Tue Jan 28 06:31:42 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 28 Jan 2025 01:31:42 -0500 Subject: [DTrace-devel] [PATCH 2/6] include: remove unnecessary include of universal.h Message-ID: Signed-off-by: Kris Van Hees --- include/dtrace/faults_defines.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/dtrace/faults_defines.h b/include/dtrace/faults_defines.h index d50477c7..73aee543 100644 --- a/include/dtrace/faults_defines.h +++ b/include/dtrace/faults_defines.h @@ -13,8 +13,6 @@ #ifndef _DTRACE_FAULTS_DEFINES_H #define _DTRACE_FAULTS_DEFINES_H -#include - /* * The constants below DTRACEFLT_LIBRARY indicate probe processing faults; * constants at or above DTRACEFLT_LIBRARY indicate faults in probe -- 2.45.2 From kris.van.hees at oracle.com Tue Jan 28 06:31:43 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 28 Jan 2025 01:31:43 -0500 Subject: [DTrace-devel] [PATCH 3/6] bpf: implement additional relocation types Message-ID: Signed-off-by: Kris Van Hees --- include/port.h | 6 ++++++ libdtrace/dt_as.c | 2 +- libdtrace/dt_cc.c | 3 ++- libdtrace/dt_dis.c | 9 ++++++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/port.h b/include/port.h index 6ce8611e..0aadacb8 100644 --- a/include/port.h +++ b/include/port.h @@ -88,6 +88,12 @@ pid_t gettid(void); #ifndef R_BPF_64_64 #define R_BPF_64_64 1 #endif +#ifndef R_BPF_64_ABS64 +#define R_BPF_64_ABS64 2 +#endif +#ifndef R_BPF_64_ABS32 +#define R_BPF_64_ABS32 3 +#endif #ifndef R_BPF_64_32 #define R_BPF_64_32 10 #endif diff --git a/libdtrace/dt_as.c b/libdtrace/dt_as.c index a634b855..d3126f9a 100644 --- a/libdtrace/dt_as.c +++ b/libdtrace/dt_as.c @@ -492,7 +492,7 @@ fail: case BPF_ST | BPF_MEM | BPF_DW: /* stdw */ case BPF_ALU64 | BPF_MOV | BPF_K: /* mov */ case BPF_ALU64 | BPF_ADD | BPF_K: /* add */ - rp->dofr_type = R_BPF_64_32; + rp->dofr_type = R_BPF_64_ABS32; break; case BPF_LD | BPF_IMM | BPF_DW: /* lddw */ rp->dofr_type = R_BPF_64_64; diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c index eebd923c..29cfbd84 100644 --- a/libdtrace/dt_cc.c +++ b/libdtrace/dt_cc.c @@ -1266,7 +1266,8 @@ dt_link_resolve(dtrace_hdl_t *dtp, dtrace_difo_t *dp) if (rp->dofr_type == R_BPF_64_64) { buf[ioff].imm = val & 0xffffffff; buf[ioff + 1].imm = val >> 32; - } else if (rp->dofr_type == R_BPF_64_32) + } else if (rp->dofr_type == R_BPF_64_32 || + rp->dofr_type == R_BPF_64_ABS32) buf[ioff].imm = (uint32_t)val; } } diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c index d983c099..b2e66754 100644 --- a/libdtrace/dt_dis.c +++ b/libdtrace/dt_dis.c @@ -639,6 +639,12 @@ dt_dis_rtab(const char *rtag, const dtrace_difo_t *dp, FILE *fp, case R_BPF_64_32: tstr = "R_BPF_INSN_DISP32"; break; + case R_BPF_64_ABS64: + tstr = "R_BPF_DATA_64"; + break; + case R_BPF_64_ABS32: + tstr = "R_BPF_DATA_32"; + break; default: tstr = "R_???"; } @@ -853,7 +859,8 @@ dt_dis_difo(const dtrace_difo_t *dp, FILE *fp, const dt_ident_t *idp, for (; cnt; cnt--, rp++) { if (rp->dofr_offset < i * sizeof(uint64_t)) continue; - if (rp->dofr_offset == i * sizeof(uint64_t)) + if (rp->dofr_offset >= i * sizeof(uint64_t) && + rp->dofr_offset < (i + 1) * sizeof(uint64_t)) rname = dt_difo_getstr(dp, rp->dofr_name); break; -- 2.45.2 From kris.van.hees at oracle.com Tue Jan 28 06:31:45 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 28 Jan 2025 01:31:45 -0500 Subject: [DTrace-devel] [PATCH 4/6] procfs: implement d_execargs() for pr_psargs translator support Message-ID: Implement d_execargs() to provide task argument string (pr_psargs) for the psinfo translator. It takes a task (struct task_struct) as argument and returns a string. psinfo->pr_psargs now simply calls d_execargs(T). Signed-off-by: Kris Van Hees --- bpf/Build | 1 + bpf/d_execargs.S | 91 ++++++++++++++++++++++++++++++++++++ dlibs/aarch64/5.11/procfs.d | 4 +- dlibs/aarch64/5.12/procfs.d | 4 +- dlibs/aarch64/5.14/procfs.d | 4 +- dlibs/aarch64/5.16/procfs.d | 4 +- dlibs/aarch64/5.2/procfs.d | 4 +- dlibs/aarch64/5.6/procfs.d | 4 +- dlibs/aarch64/6.1/procfs.d | 4 +- dlibs/aarch64/6.10/procfs.d | 4 +- dlibs/x86_64/5.11/procfs.d | 4 +- dlibs/x86_64/5.12/procfs.d | 4 +- dlibs/x86_64/5.14/procfs.d | 4 +- dlibs/x86_64/5.16/procfs.d | 4 +- dlibs/x86_64/5.2/procfs.d | 4 +- dlibs/x86_64/5.6/procfs.d | 4 +- dlibs/x86_64/6.1/procfs.d | 4 +- dlibs/x86_64/6.10/procfs.d | 4 +- include/dtrace/dif_defines.h | 7 +-- libdtrace/dt_bpf.h | 21 +++++---- libdtrace/dt_cc.c | 33 ++++++++++++- libdtrace/dt_cg.c | 9 +++- libdtrace/dt_dlibs.c | 3 ++ libdtrace/dt_open.c | 2 + libdtrace/procfs.d.in | 4 +- 25 files changed, 170 insertions(+), 65 deletions(-) create mode 100644 bpf/d_execargs.S diff --git a/bpf/Build b/bpf/Build index 3e43f4b6..9355326c 100644 --- a/bpf/Build +++ b/bpf/Build @@ -24,6 +24,7 @@ bpf_dlib_SOURCES = \ agg_lqbin.c agg_qbin.c \ basename.S \ cleanpath.S \ + d_execargs.S \ dirname.S \ get_agg.c \ get_bvar.c \ diff --git a/bpf/d_execargs.S b/bpf/d_execargs.S new file mode 100644 index 00000000..3a5b1270 --- /dev/null +++ b/bpf/d_execargs.S @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025, Oracle and/or its affiliates. + */ + +#include +#include + + .text + .align 4 + .global dt_d_execargs +dt_d_execargs: + stxdw [%fp+-8], %r1 /* save dctx to stack */ + mov %r9, %r3 /* %r9 = args */ + + mov %r6, %r2 /* set %r6 in case of error */ + jeq %r6, 0, .Lerror + + add %r6, TASK_MM /* ptr = &(T->mm) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r8, [%r9+0] /* %r8 = T->mm */ + jeq %r8, 0, .Lempty + mov %r6, %r8 + add %r6, TASK_MM_ARG_START /* ptr = &(T->mm->arg_start) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r7, [%r9+0] /* %r7 = T->mm->arg_start */ + mov %r6, %r8 + add %r6, TASK_MM_ARG_END /* ptr = &(T->mm->arg_end) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r6, [%r9+0] /* %r6 = T->mm->arg_end */ + + mov %r8, %r6 + sub %r8, %r7 /* %r8 = len = arg_end - arg_start */ + jslt %r8, 2, .Lempty + mov %r0, STRSZ + jslt %r8, %r0, .Llen_ok + mov %r8, %r0 +.Llen_ok: + + /* read data from arg_start to arg_end */ + mov %r1, %r9 + mov %r2, %r8 + mov %r3, %r7 + call BPF_FUNC_probe_read /* bpf_probe_read(&args, len + 1, arg_start) */ + jne %r0, 0, .Lerror + + /* loop over args and replace '\0' with ' ' */ + mov %r1, %r8 + sub %r1, 2 +.Lloop: + mov %r2, %r9 + add %r2, %r1 + ldxb %r0, [%r2+0] + jne %r0, 0, .Lnot_nil + stb [%r2+0], 32 +.Lnot_nil: + sub %r1, 1 + jsge %r1, 0, .Lloop + +.Ldone: + mov %r0, %r9 + exit /* return args */ +.Lerror: + ldxdw %r1, [%fp+-8] + mov %r2, PC + mov %r3, DTRACEFLT_BADADDR + mov %r4, %r6 + call dt_probe_error +.Lempty: + mov %r0, %r9 + stb [%r9+0], 0 /* args[0] = 0 */ + exit /* return args */ + .size dt_d_execargs, .-dt_d_execargs diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.11/procfs.d +++ b/dlibs/aarch64/5.11/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.12/procfs.d +++ b/dlibs/aarch64/5.12/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d index 584ac325..ef27bb70 100644 --- a/dlibs/aarch64/5.14/procfs.d +++ b/dlibs/aarch64/5.14/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d index 5aabc6f1..cad2d2c5 100644 --- a/dlibs/aarch64/5.16/procfs.d +++ b/dlibs/aarch64/5.16/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d index 683ff5a8..6b1b1b9c 100644 --- a/dlibs/aarch64/5.2/procfs.d +++ b/dlibs/aarch64/5.2/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.6/procfs.d +++ b/dlibs/aarch64/5.6/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/aarch64/6.1/procfs.d +++ b/dlibs/aarch64/6.1/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/aarch64/6.10/procfs.d +++ b/dlibs/aarch64/6.10/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d index 7274554e..c2be76d8 100644 --- a/dlibs/x86_64/5.11/procfs.d +++ b/dlibs/x86_64/5.11/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d index 7274554e..c2be76d8 100644 --- a/dlibs/x86_64/5.12/procfs.d +++ b/dlibs/x86_64/5.12/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d index d1cf90d3..28fada6d 100644 --- a/dlibs/x86_64/5.14/procfs.d +++ b/dlibs/x86_64/5.14/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d index 5aabc6f1..cad2d2c5 100644 --- a/dlibs/x86_64/5.16/procfs.d +++ b/dlibs/x86_64/5.16/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d index 35538862..08696cf7 100644 --- a/dlibs/x86_64/5.2/procfs.d +++ b/dlibs/x86_64/5.2/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d index 7274554e..c2be76d8 100644 --- a/dlibs/x86_64/5.6/procfs.d +++ b/dlibs/x86_64/5.6/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/x86_64/6.1/procfs.d +++ b/dlibs/x86_64/6.1/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/x86_64/6.10/procfs.d +++ b/dlibs/x86_64/6.10/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h index c8c1d961..cd785723 100644 --- a/include/dtrace/dif_defines.h +++ b/include/dtrace/dif_defines.h @@ -207,10 +207,11 @@ #define DIF_SUBR_INET_NTOP 41 #define DIF_SUBR_INET_NTOA 42 #define DIF_SUBR_INET_NTOA6 43 -#define DIF_SUBR_D_PATH 44 -#define DIF_SUBR_LINK_NTOP 45 +#define DIF_SUBR_LINK_NTOP 44 +#define DIF_SUBR_D_PATH 45 +#define DIF_SUBR_D_EXECARGS 46 -#define DIF_SUBR_MAX 45 +#define DIF_SUBR_MAX 46 typedef uint32_t dif_instr_t; diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h index 6518de66..85934d2d 100644 --- a/libdtrace/dt_bpf.h +++ b/libdtrace/dt_bpf.h @@ -47,15 +47,18 @@ extern "C" { #define DT_CONST_TASK_TGID 12 #define DT_CONST_TASK_REAL_PARENT 13 #define DT_CONST_TASK_COMM 14 -#define DT_CONST_MUTEX_OWNER 15 -#define DT_CONST_RWLOCK_CNTS 16 -#define DT_CONST_DCTX_RODATA 17 -#define DT_CONST_RODATA_OFF 18 -#define DT_CONST_RODATA_SIZE 19 -#define DT_CONST_ZERO_OFF 20 -#define DT_CONST_STACK_OFF 21 -#define DT_CONST_STACK_SKIP 22 -#define DT_CONST_NPROBES 23 +#define DT_CONST_TASK_MM 15 +#define DT_CONST_TASK_MM_ARG_START 16 +#define DT_CONST_TASK_MM_ARG_END 17 +#define DT_CONST_MUTEX_OWNER 18 +#define DT_CONST_RWLOCK_CNTS 19 +#define DT_CONST_DCTX_RODATA 20 +#define DT_CONST_RODATA_OFF 21 +#define DT_CONST_RODATA_SIZE 22 +#define DT_CONST_ZERO_OFF 23 +#define DT_CONST_STACK_OFF 24 +#define DT_CONST_STACK_SKIP 25 +#define DT_CONST_NPROBES 26 #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 29cfbd84..1dc119ea 100644 --- a/libdtrace/dt_cc.c +++ b/libdtrace/dt_cc.c @@ -1082,7 +1082,8 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, case DT_CONST_TASK_PID: case DT_CONST_TASK_TGID: case DT_CONST_TASK_REAL_PARENT: - case DT_CONST_TASK_COMM: { + case DT_CONST_TASK_COMM: + case DT_CONST_TASK_MM: { ctf_file_t *cfp = dtp->dt_shared_ctf; ctf_id_t type; ctf_membinfo_t ctm; @@ -1108,6 +1109,36 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, case DT_CONST_TASK_COMM: rc = ctf_member_info(cfp, type, "comm", &ctm); break; + case DT_CONST_TASK_MM: + rc = ctf_member_info(cfp, type, "mm", &ctm); + break; + } + if (rc == CTF_ERR) + goto err_ctf; + nrp->dofr_data = ctm.ctm_offset / NBBY; + continue; + } + case DT_CONST_TASK_MM_ARG_START: + case DT_CONST_TASK_MM_ARG_END: { + ctf_file_t *cfp = dtp->dt_shared_ctf; + ctf_id_t type; + ctf_membinfo_t ctm; + int rc = 0; + + if (!cfp) + return dt_set_errno(dtp, EDT_NOCTF); + + type = ctf_lookup_by_name(cfp, "struct mm_struct"); + if (type == CTF_ERR) + goto err_ctf; + + switch (idp->di_id) { + case DT_CONST_TASK_MM_ARG_START: + rc = ctf_member_info(cfp, type, "arg_start", &ctm); + break; + case DT_CONST_TASK_MM_ARG_END: + rc = ctf_member_info(cfp, type, "arg_end", &ctm); + break; } if (rc == CTF_ERR) goto err_ctf; diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index 6e74b4b0..a1a39f3f 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -3300,7 +3300,6 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) } /* built-in variables (note: args[] is handled in dt_cg_array_op) */ - /* Special case for arg0 through arg9; encode as args[n] */ if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); idx = idp->di_id - DIF_VAR_ARG0; @@ -6661,6 +6660,13 @@ dt_cg_subr_inet_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) tnp->dn_tstring = NULL; } +static void +dt_cg_subr_d_execargs(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) +{ + dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_d_execargs", 0, + DT_IGNOR, 0, DT_IGNOR, 0); +} + static void dt_cg_subr_d_path(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) { @@ -6758,6 +6764,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = { [DIF_SUBR_INET_NTOP] = &dt_cg_subr_inet_ntop, [DIF_SUBR_INET_NTOA] = &dt_cg_subr_inet_ntoa, [DIF_SUBR_INET_NTOA6] = &dt_cg_subr_inet_ntoa6, + [DIF_SUBR_D_EXECARGS] = &dt_cg_subr_d_execargs, [DIF_SUBR_D_PATH] = &dt_cg_subr_d_path, [DIF_SUBR_LINK_NTOP] = &dt_cg_subr_link_ntop, }; diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c index 07d22afd..9ad4f5e7 100644 --- a/libdtrace/dt_dlibs.c +++ b/libdtrace/dt_dlibs.c @@ -89,6 +89,9 @@ static const dt_ident_t dt_bpf_symbols[] = { DT_BPF_SYMBOL_ID(TASK_TGID, DT_IDENT_SCALAR, DT_CONST_TASK_TGID), DT_BPF_SYMBOL_ID(TASK_REAL_PARENT, DT_IDENT_SCALAR, DT_CONST_TASK_REAL_PARENT), DT_BPF_SYMBOL_ID(TASK_COMM, DT_IDENT_SCALAR, DT_CONST_TASK_COMM), + DT_BPF_SYMBOL_ID(TASK_MM, DT_IDENT_SCALAR, DT_CONST_TASK_MM), + DT_BPF_SYMBOL_ID(TASK_MM_ARG_START, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_START), + DT_BPF_SYMBOL_ID(TASK_MM_ARG_END, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_END), DT_BPF_SYMBOL_ID(MUTEX_OWNER, DT_IDENT_SCALAR, DT_CONST_MUTEX_OWNER), DT_BPF_SYMBOL_ID(RWLOCK_CNTS, DT_IDENT_SCALAR, DT_CONST_RWLOCK_CNTS), DT_BPF_SYMBOL_ID(DCTX_RODATA, DT_IDENT_SCALAR, DT_CONST_DCTX_RODATA), diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c index a0205887..c8208de6 100644 --- a/libdtrace/dt_open.c +++ b/libdtrace/dt_open.c @@ -138,6 +138,8 @@ static const dt_ident_t _dtrace_globals[] = { { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_COMMON }, DT_VERS_1_0, &dt_idops_type, "vmlinux`struct task_struct *" }, +{ "d_execargs", DT_IDENT_FUNC, 0, DIF_SUBR_D_EXECARGS, DT_ATTR_EVOLCMN, + DT_VERS_2_0, &dt_idops_func, "string(vmlinux`struct task_struct *)" }, { "d_path", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_D_PATH, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "string(struct path *)" }, { "ddi_pathname", DT_IDENT_FUNC, 0, DIF_SUBR_DDI_PATHNAME, diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in index 038cf69b..e9d50349 100644 --- a/libdtrace/procfs.d.in +++ b/libdtrace/procfs.d.in @@ -179,9 +179,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); -- 2.45.2 From kris.van.hees at oracle.com Tue Jan 28 06:31:46 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 28 Jan 2025 01:31:46 -0500 Subject: [DTrace-devel] [PATCH 5/6] procfs: add 'execargs' global variable as inline Message-ID: The 'execargs' global variable provides the psargs for curthread. Signed-off-by: Kris Van Hees --- dlibs/aarch64/5.11/procfs.d | 4 ++++ dlibs/aarch64/5.12/procfs.d | 4 ++++ dlibs/aarch64/5.14/procfs.d | 4 ++++ dlibs/aarch64/5.16/procfs.d | 4 ++++ dlibs/aarch64/5.2/procfs.d | 4 ++++ dlibs/aarch64/5.6/procfs.d | 4 ++++ dlibs/aarch64/6.1/procfs.d | 4 ++++ dlibs/aarch64/6.10/procfs.d | 4 ++++ dlibs/x86_64/5.11/procfs.d | 4 ++++ dlibs/x86_64/5.12/procfs.d | 4 ++++ dlibs/x86_64/5.14/procfs.d | 4 ++++ dlibs/x86_64/5.16/procfs.d | 4 ++++ dlibs/x86_64/5.2/procfs.d | 4 ++++ dlibs/x86_64/5.6/procfs.d | 4 ++++ dlibs/x86_64/6.1/procfs.d | 4 ++++ dlibs/x86_64/6.10/procfs.d | 4 ++++ libdtrace/procfs.d.in | 4 ++++ 17 files changed, 68 insertions(+) diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d index 70a43ddf..9c06fe1f 100644 --- a/dlibs/aarch64/5.11/procfs.d +++ b/dlibs/aarch64/5.11/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d index 70a43ddf..9c06fe1f 100644 --- a/dlibs/aarch64/5.12/procfs.d +++ b/dlibs/aarch64/5.12/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d index ef27bb70..2824d137 100644 --- a/dlibs/aarch64/5.14/procfs.d +++ b/dlibs/aarch64/5.14/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d index cad2d2c5..daf30745 100644 --- a/dlibs/aarch64/5.16/procfs.d +++ b/dlibs/aarch64/5.16/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d index 6b1b1b9c..3594e5e9 100644 --- a/dlibs/aarch64/5.2/procfs.d +++ b/dlibs/aarch64/5.2/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d index 70a43ddf..9c06fe1f 100644 --- a/dlibs/aarch64/5.6/procfs.d +++ b/dlibs/aarch64/5.6/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d index 4cb7b77c..2d52f079 100644 --- a/dlibs/aarch64/6.1/procfs.d +++ b/dlibs/aarch64/6.1/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d index 4cb7b77c..2d52f079 100644 --- a/dlibs/aarch64/6.10/procfs.d +++ b/dlibs/aarch64/6.10/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d index c2be76d8..7679db2e 100644 --- a/dlibs/x86_64/5.11/procfs.d +++ b/dlibs/x86_64/5.11/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d index c2be76d8..7679db2e 100644 --- a/dlibs/x86_64/5.12/procfs.d +++ b/dlibs/x86_64/5.12/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d index 28fada6d..3a348ebc 100644 --- a/dlibs/x86_64/5.14/procfs.d +++ b/dlibs/x86_64/5.14/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d index cad2d2c5..daf30745 100644 --- a/dlibs/x86_64/5.16/procfs.d +++ b/dlibs/x86_64/5.16/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d index 08696cf7..6ad926ee 100644 --- a/dlibs/x86_64/5.2/procfs.d +++ b/dlibs/x86_64/5.2/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d index c2be76d8..7679db2e 100644 --- a/dlibs/x86_64/5.6/procfs.d +++ b/dlibs/x86_64/5.6/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d index 4cb7b77c..2d52f079 100644 --- a/dlibs/x86_64/6.1/procfs.d +++ b/dlibs/x86_64/6.1/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d index 4cb7b77c..2d52f079 100644 --- a/dlibs/x86_64/6.10/procfs.d +++ b/dlibs/x86_64/6.10/procfs.d @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in index e9d50349..827d6b81 100644 --- a/libdtrace/procfs.d.in +++ b/libdtrace/procfs.d.in @@ -307,6 +307,10 @@ inline string root = d_path(&(curthread->fs->root)); #pragma D attributes Stable/Stable/Common root #pragma D binding "1.0" root +inline string execargs = d_execargs(curthread); +#pragma D attributes Stable/Stable/Common root +#pragma D binding "2.0" execargs + inline int CLD_EXITED = 1; #pragma D binding "1.0" CLD_EXITED inline int CLD_KILLED = 2; -- 2.45.2 From kris.van.hees at oracle.com Tue Jan 28 06:31:48 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 28 Jan 2025 01:31:48 -0500 Subject: [DTrace-devel] [PATCH 6/6] procfs: populate pr_argc, pr_argv, and pr_envp with default values Message-ID: The pr_argc, pr_argv, and pr_envp fields in psinfo are not implemented yet, so it makes sense to set them to 0 rather than not providing any translator for them. Signed-off-by: Kris Van Hees --- dlibs/aarch64/5.11/procfs.d | 8 +++----- dlibs/aarch64/5.12/procfs.d | 8 +++----- dlibs/aarch64/5.14/procfs.d | 8 +++----- dlibs/aarch64/5.16/procfs.d | 8 +++----- dlibs/aarch64/5.2/procfs.d | 8 +++----- dlibs/aarch64/5.6/procfs.d | 8 +++----- dlibs/aarch64/6.1/procfs.d | 8 +++----- dlibs/aarch64/6.10/procfs.d | 8 +++----- dlibs/x86_64/5.11/procfs.d | 8 +++----- dlibs/x86_64/5.12/procfs.d | 8 +++----- dlibs/x86_64/5.14/procfs.d | 8 +++----- dlibs/x86_64/5.16/procfs.d | 8 +++----- dlibs/x86_64/5.2/procfs.d | 8 +++----- dlibs/x86_64/5.6/procfs.d | 8 +++----- dlibs/x86_64/6.1/procfs.d | 8 +++----- dlibs/x86_64/6.10/procfs.d | 8 +++----- libdtrace/procfs.d.in | 8 +++----- test/unittest/builtinvar/tst.psinfo-bug21974606.d | 1 - test/unittest/builtinvar/tst.psinfo-bug22561297.d | 4 +--- test/unittest/builtinvar/tst.psinfo1.d | 1 - 20 files changed, 52 insertions(+), 90 deletions(-) diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d index 9c06fe1f..52b2bbe2 100644 --- a/dlibs/aarch64/5.11/procfs.d +++ b/dlibs/aarch64/5.11/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d index 9c06fe1f..52b2bbe2 100644 --- a/dlibs/aarch64/5.12/procfs.d +++ b/dlibs/aarch64/5.12/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d index 2824d137..8c05e299 100644 --- a/dlibs/aarch64/5.14/procfs.d +++ b/dlibs/aarch64/5.14/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d index daf30745..e52ab29a 100644 --- a/dlibs/aarch64/5.16/procfs.d +++ b/dlibs/aarch64/5.16/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d index 3594e5e9..4a95dfd1 100644 --- a/dlibs/aarch64/5.2/procfs.d +++ b/dlibs/aarch64/5.2/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d index 9c06fe1f..52b2bbe2 100644 --- a/dlibs/aarch64/5.6/procfs.d +++ b/dlibs/aarch64/5.6/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d index 2d52f079..4881aa5b 100644 --- a/dlibs/aarch64/6.1/procfs.d +++ b/dlibs/aarch64/6.1/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d index 2d52f079..4881aa5b 100644 --- a/dlibs/aarch64/6.10/procfs.d +++ b/dlibs/aarch64/6.10/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d index 7679db2e..96e55dc1 100644 --- a/dlibs/x86_64/5.11/procfs.d +++ b/dlibs/x86_64/5.11/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d index 7679db2e..96e55dc1 100644 --- a/dlibs/x86_64/5.12/procfs.d +++ b/dlibs/x86_64/5.12/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d index 3a348ebc..8dbf3c01 100644 --- a/dlibs/x86_64/5.14/procfs.d +++ b/dlibs/x86_64/5.14/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d index daf30745..e52ab29a 100644 --- a/dlibs/x86_64/5.16/procfs.d +++ b/dlibs/x86_64/5.16/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d index 6ad926ee..23e05c2c 100644 --- a/dlibs/x86_64/5.2/procfs.d +++ b/dlibs/x86_64/5.2/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d index 7679db2e..96e55dc1 100644 --- a/dlibs/x86_64/5.6/procfs.d +++ b/dlibs/x86_64/5.6/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d index 2d52f079..4881aa5b 100644 --- a/dlibs/x86_64/6.1/procfs.d +++ b/dlibs/x86_64/6.1/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d index 2d52f079..4881aa5b 100644 --- a/dlibs/x86_64/6.10/procfs.d +++ b/dlibs/x86_64/6.10/procfs.d @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* Not implemented yet. */ + pr_argv = 0; /* Not implemented yet. */ + pr_envp = 0; /* Not implemented yet. */ pr_dmodel = PR_MODEL_LP64; diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in index 827d6b81..d4433be4 100644 --- a/libdtrace/procfs.d.in +++ b/libdtrace/procfs.d.in @@ -181,11 +181,9 @@ translator psinfo_t < struct task_struct *T > { pr_fname = T->comm; pr_psargs = d_execargs(T); pr_wstat = 0; -/* - pr_argc = get_psinfo(T)->__psinfo(argc); - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); - */ + pr_argc = 0; /* not implemented yet */ + pr_argv = 0; /* not implemented yet */ + pr_envp = 0; /* not implemented yet */ pr_dmodel = PR_MODEL_LP64; diff --git a/test/unittest/builtinvar/tst.psinfo-bug21974606.d b/test/unittest/builtinvar/tst.psinfo-bug21974606.d index 68d9503d..03857e83 100644 --- a/test/unittest/builtinvar/tst.psinfo-bug21974606.d +++ b/test/unittest/builtinvar/tst.psinfo-bug21974606.d @@ -4,7 +4,6 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* * ASSERTION: diff --git a/test/unittest/builtinvar/tst.psinfo-bug22561297.d b/test/unittest/builtinvar/tst.psinfo-bug22561297.d index b9efd0ec..ffccf469 100644 --- a/test/unittest/builtinvar/tst.psinfo-bug22561297.d +++ b/test/unittest/builtinvar/tst.psinfo-bug22561297.d @@ -4,11 +4,9 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* - * ASSERTION: - * To print psinfo structure values from profile. + * ASSERTION: To print psinfo structure values from profile. * * SECTION: Variables/Built-in Variables */ diff --git a/test/unittest/builtinvar/tst.psinfo1.d b/test/unittest/builtinvar/tst.psinfo1.d index 9e6d5053..7c451598 100644 --- a/test/unittest/builtinvar/tst.psinfo1.d +++ b/test/unittest/builtinvar/tst.psinfo1.d @@ -4,7 +4,6 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* * ASSERTION: -- 2.45.2 From eugene.loh at oracle.com Tue Jan 28 21:36:21 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Tue, 28 Jan 2025 16:36:21 -0500 Subject: [DTrace-devel] [PATCH] test: Improve resilience of tests to ptr widths Message-ID: <20250128213621.2617-1-eugene.loh@oracle.com> From: Eugene Loh When tests are run, runtest.sh runs postprocess(), which among other things turns irreproducible hex strings (presumably offsets and pointers) into fixed strings (like "ptr") for correctness checking. In a few cases, however, there are trailing blanks to justify the right margin, meaning that the width of the hex string can cause the number of trailing blanks to vary. Improve the resilience of these tests by stripping out such trailing blanks. Signed-off-by: Eugene Loh --- test/unittest/ustack/tst.uaddr-pid0.r | 2 +- test/unittest/ustack/tst.uaddr-pid0.r.p | 4 ++++ test/unittest/ustack/tst.uaddr.r | 2 +- test/unittest/ustack/tst.uaddr.r.p | 4 ++++ test/unittest/ustack/tst.ufunc-pid0.r | 2 +- test/unittest/ustack/tst.ufunc-pid0.r.p | 4 ++++ test/unittest/ustack/tst.usym-pid0.r | 2 +- test/unittest/ustack/tst.usym-pid0.r.p | 4 ++++ 8 files changed, 20 insertions(+), 4 deletions(-) create mode 100755 test/unittest/ustack/tst.uaddr-pid0.r.p create mode 100755 test/unittest/ustack/tst.uaddr.r.p create mode 100755 test/unittest/ustack/tst.ufunc-pid0.r.p create mode 100755 test/unittest/ustack/tst.usym-pid0.r.p diff --git a/test/unittest/ustack/tst.uaddr-pid0.r b/test/unittest/ustack/tst.uaddr-pid0.r index a8e68f4e6..cc1cdbc3d 100644 --- a/test/unittest/ustack/tst.uaddr-pid0.r +++ b/test/unittest/ustack/tst.uaddr-pid0.r @@ -1 +1 @@ - {ptr} + {ptr} diff --git a/test/unittest/ustack/tst.uaddr-pid0.r.p b/test/unittest/ustack/tst.uaddr-pid0.r.p new file mode 100755 index 000000000..9203dc824 --- /dev/null +++ b/test/unittest/ustack/tst.uaddr-pid0.r.p @@ -0,0 +1,4 @@ +#!/usr/bin/gawk -f + +# remove trailing blanks +{ sub(" *$", ""); print } diff --git a/test/unittest/ustack/tst.uaddr.r b/test/unittest/ustack/tst.uaddr.r index be48a12ab..cc329e213 100644 --- a/test/unittest/ustack/tst.uaddr.r +++ b/test/unittest/ustack/tst.uaddr.r @@ -1 +1 @@ - ustack-tst-basic`myfunc_y+{ptr} + ustack-tst-basic`myfunc_y+{ptr} diff --git a/test/unittest/ustack/tst.uaddr.r.p b/test/unittest/ustack/tst.uaddr.r.p new file mode 100755 index 000000000..9203dc824 --- /dev/null +++ b/test/unittest/ustack/tst.uaddr.r.p @@ -0,0 +1,4 @@ +#!/usr/bin/gawk -f + +# remove trailing blanks +{ sub(" *$", ""); print } diff --git a/test/unittest/ustack/tst.ufunc-pid0.r b/test/unittest/ustack/tst.ufunc-pid0.r index a8e68f4e6..cc1cdbc3d 100644 --- a/test/unittest/ustack/tst.ufunc-pid0.r +++ b/test/unittest/ustack/tst.ufunc-pid0.r @@ -1 +1 @@ - {ptr} + {ptr} diff --git a/test/unittest/ustack/tst.ufunc-pid0.r.p b/test/unittest/ustack/tst.ufunc-pid0.r.p new file mode 100755 index 000000000..9203dc824 --- /dev/null +++ b/test/unittest/ustack/tst.ufunc-pid0.r.p @@ -0,0 +1,4 @@ +#!/usr/bin/gawk -f + +# remove trailing blanks +{ sub(" *$", ""); print } diff --git a/test/unittest/ustack/tst.usym-pid0.r b/test/unittest/ustack/tst.usym-pid0.r index a8e68f4e6..cc1cdbc3d 100644 --- a/test/unittest/ustack/tst.usym-pid0.r +++ b/test/unittest/ustack/tst.usym-pid0.r @@ -1 +1 @@ - {ptr} + {ptr} diff --git a/test/unittest/ustack/tst.usym-pid0.r.p b/test/unittest/ustack/tst.usym-pid0.r.p new file mode 100755 index 000000000..9203dc824 --- /dev/null +++ b/test/unittest/ustack/tst.usym-pid0.r.p @@ -0,0 +1,4 @@ +#!/usr/bin/gawk -f + +# remove trailing blanks +{ sub(" *$", ""); print } -- 2.43.5 From eugene.loh at oracle.com Tue Jan 28 23:29:43 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Tue, 28 Jan 2025 18:29:43 -0500 Subject: [DTrace-devel] [PATCH v2 1/6] bpf: separate bvar implementation into separate functions In-Reply-To: References: Message-ID: <996362c0-a77b-9265-395b-bfd9d17e9343@oracle.com> Reviewed-by: Eugene Loh If there is some quantification or other characterization of the benefit that could be added to the commit message, that would be nice. And... On 1/28/25 01:31, Kris Van Hees wrote: > The handling of builtin variables was done with a single big function > that therefore got linked into every single BPF program (twice if the > builtin variable might raise a fault). Providing separate functions > for most builtin variables reduces BPF program size significantly. > > This also reduces pressure on the BPF verifies. > > Signed-off-by: Kris Van Hees > > diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c > @@ -19,18 +19,21 @@ > # define noinline __attribute__((noinline)) > #endif > > -extern struct bpf_map_def cpuinfo; > -extern struct bpf_map_def probes; > -extern struct bpf_map_def state; > -extern struct bpf_map_def usdt_names; > - > -extern uint64_t PC; > -extern uint64_t STBSZ; > -extern uint64_t STKSIZ; > -extern uint64_t BOOTTM; > +extern struct bpf_map_def cpuinfo; > +extern struct bpf_map_def probes; > +extern struct bpf_map_def state; > +extern struct bpf_map_def usdt_names; > + > +extern uint64_t BOOTTM; > +extern uint64_t NPROBES; > +extern uint64_t PC; > +extern uint64_t STBSZ; > +extern uint64_t STKSIZ; > extern uint64_t STACK_OFF; > -extern uint64_t STACK_SKIP; > -extern uint64_t NPROBES; > +extern uint64_t STACK_SKIP; > +extern uint64_t TASK_COMM; > +extern uint64_t TASK_REAL_PARENT; > +extern uint64_t TASK_TGID; Did you intend to change the indentation on STACK_OFF as well? From eugene.loh at oracle.com Tue Jan 28 23:32:11 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Tue, 28 Jan 2025 18:32:11 -0500 Subject: [DTrace-devel] [PATCH 2/6] include: remove unnecessary include of universal.h In-Reply-To: References: Message-ID: <7fb5c8f0-ec5d-4350-6516-341c995c2683@oracle.com> Reviewed-by: Eugene Loh On 1/28/25 01:31, Kris Van Hees wrote: > Signed-off-by: Kris Van Hees > --- > include/dtrace/faults_defines.h | 2 -- > 1 file changed, 2 deletions(-) > > diff --git a/include/dtrace/faults_defines.h b/include/dtrace/faults_defines.h > index d50477c7..73aee543 100644 > --- a/include/dtrace/faults_defines.h > +++ b/include/dtrace/faults_defines.h > @@ -13,8 +13,6 @@ > #ifndef _DTRACE_FAULTS_DEFINES_H > #define _DTRACE_FAULTS_DEFINES_H > > -#include > - > /* > * The constants below DTRACEFLT_LIBRARY indicate probe processing faults; > * constants at or above DTRACEFLT_LIBRARY indicate faults in probe From kris.van.hees at oracle.com Tue Jan 28 23:35:13 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 28 Jan 2025 18:35:13 -0500 Subject: [DTrace-devel] [PATCH v2 1/6] bpf: separate bvar implementation into separate functions In-Reply-To: <996362c0-a77b-9265-395b-bfd9d17e9343@oracle.com> References: <996362c0-a77b-9265-395b-bfd9d17e9343@oracle.com> Message-ID: On Tue, Jan 28, 2025 at 06:29:43PM -0500, Eugene Loh wrote: > Reviewed-by: Eugene Loh > > If there is some quantification or other characterization of the benefit > that could be added to the commit message, that would be nice. Sure. > And... > > On 1/28/25 01:31, Kris Van Hees wrote: > > The handling of builtin variables was done with a single big function > > that therefore got linked into every single BPF program (twice if the > > builtin variable might raise a fault). Providing separate functions > > for most builtin variables reduces BPF program size significantly. > > > > This also reduces pressure on the BPF verifies. > > > > Signed-off-by: Kris Van Hees > > > > diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c > > @@ -19,18 +19,21 @@ > > # define noinline __attribute__((noinline)) > > #endif > > -extern struct bpf_map_def cpuinfo; > > -extern struct bpf_map_def probes; > > -extern struct bpf_map_def state; > > -extern struct bpf_map_def usdt_names; > > - > > -extern uint64_t PC; > > -extern uint64_t STBSZ; > > -extern uint64_t STKSIZ; > > -extern uint64_t BOOTTM; > > +extern struct bpf_map_def cpuinfo; > > +extern struct bpf_map_def probes; > > +extern struct bpf_map_def state; > > +extern struct bpf_map_def usdt_names; > > + > > +extern uint64_t BOOTTM; > > +extern uint64_t NPROBES; > > +extern uint64_t PC; > > +extern uint64_t STBSZ; > > +extern uint64_t STKSIZ; > > extern uint64_t STACK_OFF; > > -extern uint64_t STACK_SKIP; > > -extern uint64_t NPROBES; > > +extern uint64_t STACK_SKIP; > > +extern uint64_t TASK_COMM; > > +extern uint64_t TASK_REAL_PARENT; > > +extern uint64_t TASK_TGID; > > Did you intend to change the indentation on STACK_OFF as well? Woops, will fix. From eugene.loh at oracle.com Wed Jan 29 00:53:51 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Tue, 28 Jan 2025 19:53:51 -0500 Subject: [DTrace-devel] [PATCH 5/6] procfs: add 'execargs' global variable as inline In-Reply-To: References: Message-ID: <9164adb5-a6b1-a7ff-530c-6aa30fa57be3@oracle.com> I'd like a little more context here. Features:? There is a new execargs global variable.? I take it this is new to D or an extension to the D language?? Would it make sense to call this a built-in variable?? Are we also exposing a new function d_execargs()?? Shouldn't there be tests for using execargs or d_execargs() in scripts?? I cannot tell if we are adding new user features (which should be tested) or not. Testing:? I see that the following patch (6/6) lifts some XFAILs on some pr_psargs tests.? Should tst.psinfo.d be added to them? And should the removal of XFAIL for test/unittest/builtinvar/tst.psinfo-bug21974606.d be moved from that patch to this one?? And should there be correctness checks for this output:? not simply "does this script not blow up?" but actually "does this script produce correct or even just sensible output?"? I'll look more but am certainly unclear if we're talking new D features here (and if so, why they're not tested). On 1/28/25 01:31, Kris Van Hees wrote: > The 'execargs' global variable provides the psargs for curthread. > > Signed-off-by: Kris Van Hees > --- > dlibs/aarch64/5.11/procfs.d | 4 ++++ > dlibs/aarch64/5.12/procfs.d | 4 ++++ > dlibs/aarch64/5.14/procfs.d | 4 ++++ > dlibs/aarch64/5.16/procfs.d | 4 ++++ > dlibs/aarch64/5.2/procfs.d | 4 ++++ > dlibs/aarch64/5.6/procfs.d | 4 ++++ > dlibs/aarch64/6.1/procfs.d | 4 ++++ > dlibs/aarch64/6.10/procfs.d | 4 ++++ > dlibs/x86_64/5.11/procfs.d | 4 ++++ > dlibs/x86_64/5.12/procfs.d | 4 ++++ > dlibs/x86_64/5.14/procfs.d | 4 ++++ > dlibs/x86_64/5.16/procfs.d | 4 ++++ > dlibs/x86_64/5.2/procfs.d | 4 ++++ > dlibs/x86_64/5.6/procfs.d | 4 ++++ > dlibs/x86_64/6.1/procfs.d | 4 ++++ > dlibs/x86_64/6.10/procfs.d | 4 ++++ > libdtrace/procfs.d.in | 4 ++++ > 17 files changed, 68 insertions(+) > > diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d > index 70a43ddf..9c06fe1f 100644 > --- a/dlibs/aarch64/5.11/procfs.d > +++ b/dlibs/aarch64/5.11/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d > index 70a43ddf..9c06fe1f 100644 > --- a/dlibs/aarch64/5.12/procfs.d > +++ b/dlibs/aarch64/5.12/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d > index ef27bb70..2824d137 100644 > --- a/dlibs/aarch64/5.14/procfs.d > +++ b/dlibs/aarch64/5.14/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d > index cad2d2c5..daf30745 100644 > --- a/dlibs/aarch64/5.16/procfs.d > +++ b/dlibs/aarch64/5.16/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d > index 6b1b1b9c..3594e5e9 100644 > --- a/dlibs/aarch64/5.2/procfs.d > +++ b/dlibs/aarch64/5.2/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d > index 70a43ddf..9c06fe1f 100644 > --- a/dlibs/aarch64/5.6/procfs.d > +++ b/dlibs/aarch64/5.6/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d > index 4cb7b77c..2d52f079 100644 > --- a/dlibs/aarch64/6.1/procfs.d > +++ b/dlibs/aarch64/6.1/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d > index 4cb7b77c..2d52f079 100644 > --- a/dlibs/aarch64/6.10/procfs.d > +++ b/dlibs/aarch64/6.10/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d > index c2be76d8..7679db2e 100644 > --- a/dlibs/x86_64/5.11/procfs.d > +++ b/dlibs/x86_64/5.11/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d > index c2be76d8..7679db2e 100644 > --- a/dlibs/x86_64/5.12/procfs.d > +++ b/dlibs/x86_64/5.12/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d > index 28fada6d..3a348ebc 100644 > --- a/dlibs/x86_64/5.14/procfs.d > +++ b/dlibs/x86_64/5.14/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d > index cad2d2c5..daf30745 100644 > --- a/dlibs/x86_64/5.16/procfs.d > +++ b/dlibs/x86_64/5.16/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d > index 08696cf7..6ad926ee 100644 > --- a/dlibs/x86_64/5.2/procfs.d > +++ b/dlibs/x86_64/5.2/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d > index c2be76d8..7679db2e 100644 > --- a/dlibs/x86_64/5.6/procfs.d > +++ b/dlibs/x86_64/5.6/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d > index 4cb7b77c..2d52f079 100644 > --- a/dlibs/x86_64/6.1/procfs.d > +++ b/dlibs/x86_64/6.1/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d > index 4cb7b77c..2d52f079 100644 > --- a/dlibs/x86_64/6.10/procfs.d > +++ b/dlibs/x86_64/6.10/procfs.d > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; > diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in > index e9d50349..827d6b81 100644 > --- a/libdtrace/procfs.d.in > +++ b/libdtrace/procfs.d.in > @@ -307,6 +307,10 @@ inline string root = d_path(&(curthread->fs->root)); > #pragma D attributes Stable/Stable/Common root > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > +#pragma D attributes Stable/Stable/Common root > +#pragma D binding "2.0" execargs > + > inline int CLD_EXITED = 1; > #pragma D binding "1.0" CLD_EXITED > inline int CLD_KILLED = 2; From kris.van.hees at oracle.com Wed Jan 29 02:56:17 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 28 Jan 2025 21:56:17 -0500 Subject: [DTrace-devel] [PATCH 5/6] procfs: add 'execargs' global variable as inline In-Reply-To: <9164adb5-a6b1-a7ff-530c-6aa30fa57be3@oracle.com> References: <9164adb5-a6b1-a7ff-530c-6aa30fa57be3@oracle.com> Message-ID: On Tue, Jan 28, 2025 at 07:53:51PM -0500, Eugene Loh wrote: > I'd like a little more context here. > > Features:? There is a new execargs global variable.? I take it this is new > to D or an extension to the D language?? Would it make sense to call this a > built-in variable?? Are we also exposing a new function d_execargs()?? > Shouldn't there be tests for using execargs or d_execargs() in scripts?? I > cannot tell if we are adding new user features (which should be tested) or > not. Yes, execargs is essentially a new built-in variable. It is defined as an inline, simply doing d_execargs(curthread), so it is a short-hand to get to the pr_psargs info for the current task. So it depends 100% on the d_execargs() implementation, which is a function that I added in order to implement the psinfo->pr_psargs translator functionality. > Testing:? I see that the following patch (6/6) lifts some XFAILs on some > pr_psargs tests.? Should tst.psinfo.d be added to them? And should the > removal of XFAIL for test/unittest/builtinvar/tst.psinfo-bug21974606.d be > moved from that patch to this one?? And should there be correctness checks > for this output:? not simply "does this script not blow up?" but actually > "does this script produce correct or even just sensible output?"? None of the existing tests should be moved here because they do not use the ezecargs variable (since it is new). I'll add a few tests for this built-in specifically. I'd be happy to even drop this patch and not add a new built-in, but it seems somehow odd not to provide it. > I'll look more but am certainly unclear if we're talking new D features here > (and if so, why they're not tested). > On 1/28/25 01:31, Kris Van Hees wrote: > > > The 'execargs' global variable provides the psargs for curthread. > > > > Signed-off-by: Kris Van Hees > > --- > > dlibs/aarch64/5.11/procfs.d | 4 ++++ > > dlibs/aarch64/5.12/procfs.d | 4 ++++ > > dlibs/aarch64/5.14/procfs.d | 4 ++++ > > dlibs/aarch64/5.16/procfs.d | 4 ++++ > > dlibs/aarch64/5.2/procfs.d | 4 ++++ > > dlibs/aarch64/5.6/procfs.d | 4 ++++ > > dlibs/aarch64/6.1/procfs.d | 4 ++++ > > dlibs/aarch64/6.10/procfs.d | 4 ++++ > > dlibs/x86_64/5.11/procfs.d | 4 ++++ > > dlibs/x86_64/5.12/procfs.d | 4 ++++ > > dlibs/x86_64/5.14/procfs.d | 4 ++++ > > dlibs/x86_64/5.16/procfs.d | 4 ++++ > > dlibs/x86_64/5.2/procfs.d | 4 ++++ > > dlibs/x86_64/5.6/procfs.d | 4 ++++ > > dlibs/x86_64/6.1/procfs.d | 4 ++++ > > dlibs/x86_64/6.10/procfs.d | 4 ++++ > > libdtrace/procfs.d.in | 4 ++++ > > 17 files changed, 68 insertions(+) > > > > diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d > > index 70a43ddf..9c06fe1f 100644 > > --- a/dlibs/aarch64/5.11/procfs.d > > +++ b/dlibs/aarch64/5.11/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d > > index 70a43ddf..9c06fe1f 100644 > > --- a/dlibs/aarch64/5.12/procfs.d > > +++ b/dlibs/aarch64/5.12/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d > > index ef27bb70..2824d137 100644 > > --- a/dlibs/aarch64/5.14/procfs.d > > +++ b/dlibs/aarch64/5.14/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d > > index cad2d2c5..daf30745 100644 > > --- a/dlibs/aarch64/5.16/procfs.d > > +++ b/dlibs/aarch64/5.16/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d > > index 6b1b1b9c..3594e5e9 100644 > > --- a/dlibs/aarch64/5.2/procfs.d > > +++ b/dlibs/aarch64/5.2/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d > > index 70a43ddf..9c06fe1f 100644 > > --- a/dlibs/aarch64/5.6/procfs.d > > +++ b/dlibs/aarch64/5.6/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d > > index 4cb7b77c..2d52f079 100644 > > --- a/dlibs/aarch64/6.1/procfs.d > > +++ b/dlibs/aarch64/6.1/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d > > index 4cb7b77c..2d52f079 100644 > > --- a/dlibs/aarch64/6.10/procfs.d > > +++ b/dlibs/aarch64/6.10/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d > > index c2be76d8..7679db2e 100644 > > --- a/dlibs/x86_64/5.11/procfs.d > > +++ b/dlibs/x86_64/5.11/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d > > index c2be76d8..7679db2e 100644 > > --- a/dlibs/x86_64/5.12/procfs.d > > +++ b/dlibs/x86_64/5.12/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d > > index 28fada6d..3a348ebc 100644 > > --- a/dlibs/x86_64/5.14/procfs.d > > +++ b/dlibs/x86_64/5.14/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d > > index cad2d2c5..daf30745 100644 > > --- a/dlibs/x86_64/5.16/procfs.d > > +++ b/dlibs/x86_64/5.16/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d > > index 08696cf7..6ad926ee 100644 > > --- a/dlibs/x86_64/5.2/procfs.d > > +++ b/dlibs/x86_64/5.2/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d > > index c2be76d8..7679db2e 100644 > > --- a/dlibs/x86_64/5.6/procfs.d > > +++ b/dlibs/x86_64/5.6/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d > > index 4cb7b77c..2d52f079 100644 > > --- a/dlibs/x86_64/6.1/procfs.d > > +++ b/dlibs/x86_64/6.1/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d > > index 4cb7b77c..2d52f079 100644 > > --- a/dlibs/x86_64/6.10/procfs.d > > +++ b/dlibs/x86_64/6.10/procfs.d > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; > > diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in > > index e9d50349..827d6b81 100644 > > --- a/libdtrace/procfs.d.in > > +++ b/libdtrace/procfs.d.in > > @@ -307,6 +307,10 @@ inline string root = d_path(&(curthread->fs->root)); > > #pragma D attributes Stable/Stable/Common root > > #pragma D binding "1.0" root > > +inline string execargs = d_execargs(curthread); > > +#pragma D attributes Stable/Stable/Common root > > +#pragma D binding "2.0" execargs > > + > > inline int CLD_EXITED = 1; > > #pragma D binding "1.0" CLD_EXITED > > inline int CLD_KILLED = 2; From kris.van.hees at oracle.com Wed Jan 29 06:45:52 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Wed, 29 Jan 2025 01:45:52 -0500 Subject: [DTrace-devel] [PATCH 5/6] procfs: add 'execargs' global variable as inline In-Reply-To: References: <9164adb5-a6b1-a7ff-530c-6aa30fa57be3@oracle.com> Message-ID: Actually, I am withdrawing this patch. I forgot that we have curpsinfo as a builtin, so execargs can be obtained as curpsinfo->pr_psargs, so there is no need for a shorthand. On Tue, Jan 28, 2025 at 09:56:17PM -0500, Kris Van Hees wrote: > On Tue, Jan 28, 2025 at 07:53:51PM -0500, Eugene Loh wrote: > > I'd like a little more context here. > > > > Features:? There is a new execargs global variable.? I take it this is new > > to D or an extension to the D language?? Would it make sense to call this a > > built-in variable?? Are we also exposing a new function d_execargs()?? > > Shouldn't there be tests for using execargs or d_execargs() in scripts?? I > > cannot tell if we are adding new user features (which should be tested) or > > not. > > Yes, execargs is essentially a new built-in variable. It is defined as an > inline, simply doing d_execargs(curthread), so it is a short-hand to get to > the pr_psargs info for the current task. > > So it depends 100% on the d_execargs() implementation, which is a function > that I added in order to implement the psinfo->pr_psargs translator > functionality. > > > Testing:? I see that the following patch (6/6) lifts some XFAILs on some > > pr_psargs tests.? Should tst.psinfo.d be added to them? And should the > > removal of XFAIL for test/unittest/builtinvar/tst.psinfo-bug21974606.d be > > moved from that patch to this one?? And should there be correctness checks > > for this output:? not simply "does this script not blow up?" but actually > > "does this script produce correct or even just sensible output?"? > > None of the existing tests should be moved here because they do not use the > ezecargs variable (since it is new). I'll add a few tests for this built-in > specifically. I'd be happy to even drop this patch and not add a new > built-in, but it seems somehow odd not to provide it. > > > I'll look more but am certainly unclear if we're talking new D features here > > (and if so, why they're not tested). > > > On 1/28/25 01:31, Kris Van Hees wrote: > > > > > The 'execargs' global variable provides the psargs for curthread. > > > > > > Signed-off-by: Kris Van Hees > > > --- > > > dlibs/aarch64/5.11/procfs.d | 4 ++++ > > > dlibs/aarch64/5.12/procfs.d | 4 ++++ > > > dlibs/aarch64/5.14/procfs.d | 4 ++++ > > > dlibs/aarch64/5.16/procfs.d | 4 ++++ > > > dlibs/aarch64/5.2/procfs.d | 4 ++++ > > > dlibs/aarch64/5.6/procfs.d | 4 ++++ > > > dlibs/aarch64/6.1/procfs.d | 4 ++++ > > > dlibs/aarch64/6.10/procfs.d | 4 ++++ > > > dlibs/x86_64/5.11/procfs.d | 4 ++++ > > > dlibs/x86_64/5.12/procfs.d | 4 ++++ > > > dlibs/x86_64/5.14/procfs.d | 4 ++++ > > > dlibs/x86_64/5.16/procfs.d | 4 ++++ > > > dlibs/x86_64/5.2/procfs.d | 4 ++++ > > > dlibs/x86_64/5.6/procfs.d | 4 ++++ > > > dlibs/x86_64/6.1/procfs.d | 4 ++++ > > > dlibs/x86_64/6.10/procfs.d | 4 ++++ > > > libdtrace/procfs.d.in | 4 ++++ > > > 17 files changed, 68 insertions(+) > > > > > > diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d > > > index 70a43ddf..9c06fe1f 100644 > > > --- a/dlibs/aarch64/5.11/procfs.d > > > +++ b/dlibs/aarch64/5.11/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d > > > index 70a43ddf..9c06fe1f 100644 > > > --- a/dlibs/aarch64/5.12/procfs.d > > > +++ b/dlibs/aarch64/5.12/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d > > > index ef27bb70..2824d137 100644 > > > --- a/dlibs/aarch64/5.14/procfs.d > > > +++ b/dlibs/aarch64/5.14/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d > > > index cad2d2c5..daf30745 100644 > > > --- a/dlibs/aarch64/5.16/procfs.d > > > +++ b/dlibs/aarch64/5.16/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d > > > index 6b1b1b9c..3594e5e9 100644 > > > --- a/dlibs/aarch64/5.2/procfs.d > > > +++ b/dlibs/aarch64/5.2/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d > > > index 70a43ddf..9c06fe1f 100644 > > > --- a/dlibs/aarch64/5.6/procfs.d > > > +++ b/dlibs/aarch64/5.6/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d > > > index 4cb7b77c..2d52f079 100644 > > > --- a/dlibs/aarch64/6.1/procfs.d > > > +++ b/dlibs/aarch64/6.1/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d > > > index 4cb7b77c..2d52f079 100644 > > > --- a/dlibs/aarch64/6.10/procfs.d > > > +++ b/dlibs/aarch64/6.10/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d > > > index c2be76d8..7679db2e 100644 > > > --- a/dlibs/x86_64/5.11/procfs.d > > > +++ b/dlibs/x86_64/5.11/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d > > > index c2be76d8..7679db2e 100644 > > > --- a/dlibs/x86_64/5.12/procfs.d > > > +++ b/dlibs/x86_64/5.12/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d > > > index 28fada6d..3a348ebc 100644 > > > --- a/dlibs/x86_64/5.14/procfs.d > > > +++ b/dlibs/x86_64/5.14/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d > > > index cad2d2c5..daf30745 100644 > > > --- a/dlibs/x86_64/5.16/procfs.d > > > +++ b/dlibs/x86_64/5.16/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d > > > index 08696cf7..6ad926ee 100644 > > > --- a/dlibs/x86_64/5.2/procfs.d > > > +++ b/dlibs/x86_64/5.2/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d > > > index c2be76d8..7679db2e 100644 > > > --- a/dlibs/x86_64/5.6/procfs.d > > > +++ b/dlibs/x86_64/5.6/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d > > > index 4cb7b77c..2d52f079 100644 > > > --- a/dlibs/x86_64/6.1/procfs.d > > > +++ b/dlibs/x86_64/6.1/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d > > > index 4cb7b77c..2d52f079 100644 > > > --- a/dlibs/x86_64/6.10/procfs.d > > > +++ b/dlibs/x86_64/6.10/procfs.d > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; > > > diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in > > > index e9d50349..827d6b81 100644 > > > --- a/libdtrace/procfs.d.in > > > +++ b/libdtrace/procfs.d.in > > > @@ -307,6 +307,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > #pragma D attributes Stable/Stable/Common root > > > #pragma D binding "1.0" root > > > +inline string execargs = d_execargs(curthread); > > > +#pragma D attributes Stable/Stable/Common root > > > +#pragma D binding "2.0" execargs > > > + > > > inline int CLD_EXITED = 1; > > > #pragma D binding "1.0" CLD_EXITED > > > inline int CLD_KILLED = 2; From kris.van.hees at oracle.com Wed Jan 29 07:00:20 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Wed, 29 Jan 2025 02:00:20 -0500 Subject: [DTrace-devel] [PATCH v2 4/6] procfs: implement d_execargs() for pr_psargs translator support Message-ID: Implement d_execargs() to provide task argument string (pr_psargs) for the psinfo translator. It takes a task (struct task_struct) as argument and returns a string. psinfo->pr_psargs now simply calls d_execargs(T). Signed-off-by: Kris Van Hees --- bpf/Build | 1 + bpf/d_execargs.S | 91 +++++++++++++++++++ dlibs/aarch64/5.11/procfs.d | 4 +- dlibs/aarch64/5.12/procfs.d | 4 +- dlibs/aarch64/5.14/procfs.d | 4 +- dlibs/aarch64/5.16/procfs.d | 4 +- dlibs/aarch64/5.2/procfs.d | 4 +- dlibs/aarch64/5.6/procfs.d | 4 +- dlibs/aarch64/6.1/procfs.d | 4 +- dlibs/aarch64/6.10/procfs.d | 4 +- dlibs/x86_64/5.11/procfs.d | 4 +- dlibs/x86_64/5.12/procfs.d | 4 +- dlibs/x86_64/5.14/procfs.d | 4 +- dlibs/x86_64/5.16/procfs.d | 4 +- dlibs/x86_64/5.2/procfs.d | 4 +- dlibs/x86_64/5.6/procfs.d | 4 +- dlibs/x86_64/6.1/procfs.d | 4 +- dlibs/x86_64/6.10/procfs.d | 4 +- include/dtrace/dif_defines.h | 7 +- libdtrace/dt_bpf.h | 21 +++-- libdtrace/dt_cc.c | 33 ++++++- libdtrace/dt_cg.c | 9 +- libdtrace/dt_dlibs.c | 3 + libdtrace/dt_open.c | 2 + libdtrace/procfs.d.in | 4 +- .../d_execargs/err.D_PROTO_ARG.scalar_arg.d | 16 ++++ .../d_execargs/err.D_PROTO_ARG.scalar_arg.r | 4 + .../d_execargs/err.D_PROTO_ARG.string_arg.d | 16 ++++ .../d_execargs/err.D_PROTO_ARG.string_arg.r | 4 + .../d_execargs/err.D_PROTO_ARG.wrong_ptr.d | 16 ++++ .../d_execargs/err.D_PROTO_ARG.wrong_ptr.r | 4 + .../d_execargs/err.D_PROTO_LEN.missing_arg.d | 16 ++++ .../d_execargs/err.D_PROTO_LEN.missing_arg.r | 2 + .../err.D_PROTO_LEN.too_many_args.d | 16 ++++ .../err.D_PROTO_LEN.too_many_args.r | 2 + .../funcs/d_execargs/tst.d_execargs.d | 31 +++++++ .../funcs/d_execargs/tst.d_execargs.r | 2 + test/unittest/proc/tst.pr_psargs.d | 31 +++++++ test/unittest/proc/tst.pr_psargs.r | 9 ++ 39 files changed, 339 insertions(+), 65 deletions(-) create mode 100644 bpf/d_execargs.S create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.d create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.r create mode 100644 test/unittest/proc/tst.pr_psargs.d create mode 100644 test/unittest/proc/tst.pr_psargs.r diff --git a/bpf/Build b/bpf/Build index 3e43f4b6..9355326c 100644 --- a/bpf/Build +++ b/bpf/Build @@ -24,6 +24,7 @@ bpf_dlib_SOURCES = \ agg_lqbin.c agg_qbin.c \ basename.S \ cleanpath.S \ + d_execargs.S \ dirname.S \ get_agg.c \ get_bvar.c \ diff --git a/bpf/d_execargs.S b/bpf/d_execargs.S new file mode 100644 index 00000000..3a5b1270 --- /dev/null +++ b/bpf/d_execargs.S @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025, Oracle and/or its affiliates. + */ + +#include +#include + + .text + .align 4 + .global dt_d_execargs +dt_d_execargs: + stxdw [%fp+-8], %r1 /* save dctx to stack */ + mov %r9, %r3 /* %r9 = args */ + + mov %r6, %r2 /* set %r6 in case of error */ + jeq %r6, 0, .Lerror + + add %r6, TASK_MM /* ptr = &(T->mm) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r8, [%r9+0] /* %r8 = T->mm */ + jeq %r8, 0, .Lempty + mov %r6, %r8 + add %r6, TASK_MM_ARG_START /* ptr = &(T->mm->arg_start) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r7, [%r9+0] /* %r7 = T->mm->arg_start */ + mov %r6, %r8 + add %r6, TASK_MM_ARG_END /* ptr = &(T->mm->arg_end) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r6, [%r9+0] /* %r6 = T->mm->arg_end */ + + mov %r8, %r6 + sub %r8, %r7 /* %r8 = len = arg_end - arg_start */ + jslt %r8, 2, .Lempty + mov %r0, STRSZ + jslt %r8, %r0, .Llen_ok + mov %r8, %r0 +.Llen_ok: + + /* read data from arg_start to arg_end */ + mov %r1, %r9 + mov %r2, %r8 + mov %r3, %r7 + call BPF_FUNC_probe_read /* bpf_probe_read(&args, len + 1, arg_start) */ + jne %r0, 0, .Lerror + + /* loop over args and replace '\0' with ' ' */ + mov %r1, %r8 + sub %r1, 2 +.Lloop: + mov %r2, %r9 + add %r2, %r1 + ldxb %r0, [%r2+0] + jne %r0, 0, .Lnot_nil + stb [%r2+0], 32 +.Lnot_nil: + sub %r1, 1 + jsge %r1, 0, .Lloop + +.Ldone: + mov %r0, %r9 + exit /* return args */ +.Lerror: + ldxdw %r1, [%fp+-8] + mov %r2, PC + mov %r3, DTRACEFLT_BADADDR + mov %r4, %r6 + call dt_probe_error +.Lempty: + mov %r0, %r9 + stb [%r9+0], 0 /* args[0] = 0 */ + exit /* return args */ + .size dt_d_execargs, .-dt_d_execargs diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.11/procfs.d +++ b/dlibs/aarch64/5.11/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.12/procfs.d +++ b/dlibs/aarch64/5.12/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d index 584ac325..ef27bb70 100644 --- a/dlibs/aarch64/5.14/procfs.d +++ b/dlibs/aarch64/5.14/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d index 5aabc6f1..cad2d2c5 100644 --- a/dlibs/aarch64/5.16/procfs.d +++ b/dlibs/aarch64/5.16/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d index 683ff5a8..6b1b1b9c 100644 --- a/dlibs/aarch64/5.2/procfs.d +++ b/dlibs/aarch64/5.2/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.6/procfs.d +++ b/dlibs/aarch64/5.6/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/aarch64/6.1/procfs.d +++ b/dlibs/aarch64/6.1/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/aarch64/6.10/procfs.d +++ b/dlibs/aarch64/6.10/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d index 7274554e..c2be76d8 100644 --- a/dlibs/x86_64/5.11/procfs.d +++ b/dlibs/x86_64/5.11/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d index 7274554e..c2be76d8 100644 --- a/dlibs/x86_64/5.12/procfs.d +++ b/dlibs/x86_64/5.12/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d index d1cf90d3..28fada6d 100644 --- a/dlibs/x86_64/5.14/procfs.d +++ b/dlibs/x86_64/5.14/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d index 5aabc6f1..cad2d2c5 100644 --- a/dlibs/x86_64/5.16/procfs.d +++ b/dlibs/x86_64/5.16/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d index 35538862..08696cf7 100644 --- a/dlibs/x86_64/5.2/procfs.d +++ b/dlibs/x86_64/5.2/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d index 7274554e..c2be76d8 100644 --- a/dlibs/x86_64/5.6/procfs.d +++ b/dlibs/x86_64/5.6/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/x86_64/6.1/procfs.d +++ b/dlibs/x86_64/6.1/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/x86_64/6.10/procfs.d +++ b/dlibs/x86_64/6.10/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h index c8c1d961..cd785723 100644 --- a/include/dtrace/dif_defines.h +++ b/include/dtrace/dif_defines.h @@ -207,10 +207,11 @@ #define DIF_SUBR_INET_NTOP 41 #define DIF_SUBR_INET_NTOA 42 #define DIF_SUBR_INET_NTOA6 43 -#define DIF_SUBR_D_PATH 44 -#define DIF_SUBR_LINK_NTOP 45 +#define DIF_SUBR_LINK_NTOP 44 +#define DIF_SUBR_D_PATH 45 +#define DIF_SUBR_D_EXECARGS 46 -#define DIF_SUBR_MAX 45 +#define DIF_SUBR_MAX 46 typedef uint32_t dif_instr_t; diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h index 6518de66..85934d2d 100644 --- a/libdtrace/dt_bpf.h +++ b/libdtrace/dt_bpf.h @@ -47,15 +47,18 @@ extern "C" { #define DT_CONST_TASK_TGID 12 #define DT_CONST_TASK_REAL_PARENT 13 #define DT_CONST_TASK_COMM 14 -#define DT_CONST_MUTEX_OWNER 15 -#define DT_CONST_RWLOCK_CNTS 16 -#define DT_CONST_DCTX_RODATA 17 -#define DT_CONST_RODATA_OFF 18 -#define DT_CONST_RODATA_SIZE 19 -#define DT_CONST_ZERO_OFF 20 -#define DT_CONST_STACK_OFF 21 -#define DT_CONST_STACK_SKIP 22 -#define DT_CONST_NPROBES 23 +#define DT_CONST_TASK_MM 15 +#define DT_CONST_TASK_MM_ARG_START 16 +#define DT_CONST_TASK_MM_ARG_END 17 +#define DT_CONST_MUTEX_OWNER 18 +#define DT_CONST_RWLOCK_CNTS 19 +#define DT_CONST_DCTX_RODATA 20 +#define DT_CONST_RODATA_OFF 21 +#define DT_CONST_RODATA_SIZE 22 +#define DT_CONST_ZERO_OFF 23 +#define DT_CONST_STACK_OFF 24 +#define DT_CONST_STACK_SKIP 25 +#define DT_CONST_NPROBES 26 #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 29cfbd84..1dc119ea 100644 --- a/libdtrace/dt_cc.c +++ b/libdtrace/dt_cc.c @@ -1082,7 +1082,8 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, case DT_CONST_TASK_PID: case DT_CONST_TASK_TGID: case DT_CONST_TASK_REAL_PARENT: - case DT_CONST_TASK_COMM: { + case DT_CONST_TASK_COMM: + case DT_CONST_TASK_MM: { ctf_file_t *cfp = dtp->dt_shared_ctf; ctf_id_t type; ctf_membinfo_t ctm; @@ -1108,6 +1109,36 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, case DT_CONST_TASK_COMM: rc = ctf_member_info(cfp, type, "comm", &ctm); break; + case DT_CONST_TASK_MM: + rc = ctf_member_info(cfp, type, "mm", &ctm); + break; + } + if (rc == CTF_ERR) + goto err_ctf; + nrp->dofr_data = ctm.ctm_offset / NBBY; + continue; + } + case DT_CONST_TASK_MM_ARG_START: + case DT_CONST_TASK_MM_ARG_END: { + ctf_file_t *cfp = dtp->dt_shared_ctf; + ctf_id_t type; + ctf_membinfo_t ctm; + int rc = 0; + + if (!cfp) + return dt_set_errno(dtp, EDT_NOCTF); + + type = ctf_lookup_by_name(cfp, "struct mm_struct"); + if (type == CTF_ERR) + goto err_ctf; + + switch (idp->di_id) { + case DT_CONST_TASK_MM_ARG_START: + rc = ctf_member_info(cfp, type, "arg_start", &ctm); + break; + case DT_CONST_TASK_MM_ARG_END: + rc = ctf_member_info(cfp, type, "arg_end", &ctm); + break; } if (rc == CTF_ERR) goto err_ctf; diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index 6e74b4b0..a1a39f3f 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -3300,7 +3300,6 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) } /* built-in variables (note: args[] is handled in dt_cg_array_op) */ - /* Special case for arg0 through arg9; encode as args[n] */ if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); idx = idp->di_id - DIF_VAR_ARG0; @@ -6661,6 +6660,13 @@ dt_cg_subr_inet_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) tnp->dn_tstring = NULL; } +static void +dt_cg_subr_d_execargs(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) +{ + dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_d_execargs", 0, + DT_IGNOR, 0, DT_IGNOR, 0); +} + static void dt_cg_subr_d_path(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) { @@ -6758,6 +6764,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = { [DIF_SUBR_INET_NTOP] = &dt_cg_subr_inet_ntop, [DIF_SUBR_INET_NTOA] = &dt_cg_subr_inet_ntoa, [DIF_SUBR_INET_NTOA6] = &dt_cg_subr_inet_ntoa6, + [DIF_SUBR_D_EXECARGS] = &dt_cg_subr_d_execargs, [DIF_SUBR_D_PATH] = &dt_cg_subr_d_path, [DIF_SUBR_LINK_NTOP] = &dt_cg_subr_link_ntop, }; diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c index 07d22afd..9ad4f5e7 100644 --- a/libdtrace/dt_dlibs.c +++ b/libdtrace/dt_dlibs.c @@ -89,6 +89,9 @@ static const dt_ident_t dt_bpf_symbols[] = { DT_BPF_SYMBOL_ID(TASK_TGID, DT_IDENT_SCALAR, DT_CONST_TASK_TGID), DT_BPF_SYMBOL_ID(TASK_REAL_PARENT, DT_IDENT_SCALAR, DT_CONST_TASK_REAL_PARENT), DT_BPF_SYMBOL_ID(TASK_COMM, DT_IDENT_SCALAR, DT_CONST_TASK_COMM), + DT_BPF_SYMBOL_ID(TASK_MM, DT_IDENT_SCALAR, DT_CONST_TASK_MM), + DT_BPF_SYMBOL_ID(TASK_MM_ARG_START, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_START), + DT_BPF_SYMBOL_ID(TASK_MM_ARG_END, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_END), DT_BPF_SYMBOL_ID(MUTEX_OWNER, DT_IDENT_SCALAR, DT_CONST_MUTEX_OWNER), DT_BPF_SYMBOL_ID(RWLOCK_CNTS, DT_IDENT_SCALAR, DT_CONST_RWLOCK_CNTS), DT_BPF_SYMBOL_ID(DCTX_RODATA, DT_IDENT_SCALAR, DT_CONST_DCTX_RODATA), diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c index a0205887..c8208de6 100644 --- a/libdtrace/dt_open.c +++ b/libdtrace/dt_open.c @@ -138,6 +138,8 @@ static const dt_ident_t _dtrace_globals[] = { { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_COMMON }, DT_VERS_1_0, &dt_idops_type, "vmlinux`struct task_struct *" }, +{ "d_execargs", DT_IDENT_FUNC, 0, DIF_SUBR_D_EXECARGS, DT_ATTR_EVOLCMN, + DT_VERS_2_0, &dt_idops_func, "string(vmlinux`struct task_struct *)" }, { "d_path", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_D_PATH, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "string(struct path *)" }, { "ddi_pathname", DT_IDENT_FUNC, 0, DIF_SUBR_DDI_PATHNAME, diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in index 038cf69b..e9d50349 100644 --- a/libdtrace/procfs.d.in +++ b/libdtrace/procfs.d.in @@ -179,9 +179,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d new file mode 100644 index 00000000..c707184d --- /dev/null +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d @@ -0,0 +1,16 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: The argument to d_execargs() should be a (struct task_struct *). + */ + +BEGIN +{ + trace(d_execargs(1)); + exit(0); +} diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r new file mode 100644 index 00000000..0e9cda07 --- /dev/null +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r @@ -0,0 +1,4 @@ +-- @@stderr -- +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: + prototype: struct task_struct * + argument: int diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d new file mode 100644 index 00000000..ba419689 --- /dev/null +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d @@ -0,0 +1,16 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: The argument to d_execargs() should be (struct task_struct *). + */ + +BEGIN +{ + trace(d_execargs("a")); + exit(0); +} diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r new file mode 100644 index 00000000..ac1c1401 --- /dev/null +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r @@ -0,0 +1,4 @@ +-- @@stderr -- +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: + prototype: struct task_struct * + argument: string diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d new file mode 100644 index 00000000..473e35e4 --- /dev/null +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d @@ -0,0 +1,16 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: The argument to d_execargs() should be (struct task_struct *). + */ + +BEGIN +{ + trace(d_execargs(curthread->mm)); + exit(0); +} diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r new file mode 100644 index 00000000..842371a3 --- /dev/null +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r @@ -0,0 +1,4 @@ +-- @@stderr -- +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: + prototype: struct task_struct * + argument: struct mm_struct * diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d new file mode 100644 index 00000000..86b1b237 --- /dev/null +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d @@ -0,0 +1,16 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: d_execargs() requires an argument + */ + +BEGIN +{ + trace(d_execargs()); + exit(0); +} diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r new file mode 100644 index 00000000..a4fcd162 --- /dev/null +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r @@ -0,0 +1,2 @@ +-- @@stderr -- +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 0 args passed, 1 expected diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d new file mode 100644 index 00000000..3add63f6 --- /dev/null +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d @@ -0,0 +1,16 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: The d_execargs() subroutine accepts no more than one argument. + */ + +BEGIN +{ + trace(d_execargs(curthread, 1)); + exit(0); +} diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r new file mode 100644 index 00000000..f5a982ff --- /dev/null +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r @@ -0,0 +1,2 @@ +-- @@stderr -- +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 2 args passed, 1 expected diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.d b/test/unittest/funcs/d_execargs/tst.d_execargs.d new file mode 100644 index 00000000..b8b141aa --- /dev/null +++ b/test/unittest/funcs/d_execargs/tst.d_execargs.d @@ -0,0 +1,31 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: d_execargs() provides correct results. + */ + +#pragma D option destructive +#pragma D option quiet + +BEGIN +{ + mypid = pid; + system("/bin/echo TEST"); +} + +proc:::exec-success +/progenyof(mypid) && d_execargs(curthread) == "/bin/echo TEST"/ +{ + trace(d_execargs(curthread)); + exit(0); +} + +tick-1s +{ + exit(1); +} diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.r b/test/unittest/funcs/d_execargs/tst.d_execargs.r new file mode 100644 index 00000000..d8ff6689 --- /dev/null +++ b/test/unittest/funcs/d_execargs/tst.d_execargs.r @@ -0,0 +1,2 @@ +TEST +/bin/echo TEST diff --git a/test/unittest/proc/tst.pr_psargs.d b/test/unittest/proc/tst.pr_psargs.d new file mode 100644 index 00000000..902ac1a3 --- /dev/null +++ b/test/unittest/proc/tst.pr_psargs.d @@ -0,0 +1,31 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: psinfo->pr_psargs provides correct results. + */ + +#pragma D option destructive +#pragma D option quiet + +BEGIN +{ + mypid = pid; + system("/bin/echo TEST"); +} + +proc:::exec-success +/progenyof(mypid) && curpsinfo->pr_psargs == "/bin/echo TEST"/ +{ + trace(curpsinfo->pr_psargs); + exit(0); +} + +tick-1s +{ + exit(1); +} diff --git a/test/unittest/proc/tst.pr_psargs.r b/test/unittest/proc/tst.pr_psargs.r new file mode 100644 index 00000000..397c8717 --- /dev/null +++ b/test/unittest/proc/tst.pr_psargs.r @@ -0,0 +1,9 @@ +TEST + + 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef + 0: 2f 62 69 6e 2f 65 63 68 6f 20 54 45 53 54 00 00 /bin/echo TEST.. + 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + -- 2.45.2 From alan.maguire at oracle.com Wed Jan 29 14:43:57 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Wed, 29 Jan 2025 14:43:57 +0000 Subject: [DTrace-devel] [PATCH 0/4] ELF note-based USDT support Message-ID: <20250129144401.505186-1-alan.maguire@oracle.com> This series adds support (patch 1) for ELF-note defined USDT probes in binaries and libraries; patches 2-4 add tests. Basic pid-specific USDT support is added; i.e. it is necessary to specify the target pid in the provider name such as "example1234" ; future work could add pid wildcarding. ELF note defined probes are defined by including sys/sdt.h from the systemtap-sdt-devel package, and are defined in C programs via DTRACE_PROBEn(provider, probe, [args...]) See the tests for concrete examples. For python, go, etc, USDT probes can be added via libstapsdt [1] and associated language-specific bindings. This allows users of those languages to add USDT probes too. For example, the following example program adds a "pythonapp" probe "firstProbe" using the python-specific libstapsdt binding: #!/usr/bin/python3 from time import sleep import stapsdt provider = stapsdt.Provider("pythonapp") probe = provider.add_probe( "firstProbe", stapsdt.ArgTypes.uint64, stapsdt.ArgTypes.int32) provider.load() while True: print("Firing probe...") if probe.fire("My little probe", 42): print("Probe fired!") sleep(1) We can then trace this via dtrace: # dtrace -n 'pythonapp503211:::* { printf("args %s, %d\n", copyinstr(arg0), arg1); }' dtrace: description 'pythonapp503211:::* ' matched 1 probe CPU ID FUNCTION:NAME 6 286628 :firstProbe args My little probe, 42 [1] https://github.com/linux-usdt/libstapsdt Alan Maguire (4): USDT: support ELF-note-defined probes selftests/usdt: add test for USDT note-defined probe firing, args selftests/usdt: add test for USDT notes in shared library selftests/usdt: add test covering different forms of USDT note args include/dtrace/pid.h | 29 ++ libdtrace/dt_cg.c | 47 ++ libdtrace/dt_cg.h | 1 + libdtrace/dt_pid.c | 466 ++++++++++++++++++++ libdtrace/dt_prov_uprobe.c | 19 +- test/unittest/usdt/sdt_notes.h | 504 ++++++++++++++++++++++ test/unittest/usdt/tst.usdt-notes-args.r | 2 + test/unittest/usdt/tst.usdt-notes-args.sh | 51 +++ test/unittest/usdt/tst.usdt-notes-lib.r | 14 + test/unittest/usdt/tst.usdt-notes-lib.sh | 145 +++++++ test/unittest/usdt/tst.usdt-notes.r | 14 + test/unittest/usdt/tst.usdt-notes.sh | 121 ++++++ 12 files changed, 1406 insertions(+), 7 deletions(-) create mode 100644 test/unittest/usdt/sdt_notes.h create mode 100644 test/unittest/usdt/tst.usdt-notes-args.r create mode 100755 test/unittest/usdt/tst.usdt-notes-args.sh create mode 100644 test/unittest/usdt/tst.usdt-notes-lib.r create mode 100755 test/unittest/usdt/tst.usdt-notes-lib.sh create mode 100644 test/unittest/usdt/tst.usdt-notes.r create mode 100755 test/unittest/usdt/tst.usdt-notes.sh -- 2.43.5 From alan.maguire at oracle.com Wed Jan 29 14:43:58 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Wed, 29 Jan 2025 14:43:58 +0000 Subject: [DTrace-devel] [PATCH 1/4] USDT: support ELF-note-defined probes In-Reply-To: <20250129144401.505186-1-alan.maguire@oracle.com> References: <20250129144401.505186-1-alan.maguire@oracle.com> Message-ID: <20250129144401.505186-2-alan.maguire@oracle.com> As well as using dtrace -G to generate USDT probes, they can be added via ELF notes describing the probe. Read ELF notes from /proc//exe and associated libraries, and parse them to retrieve uprobe address and argument-related info to create the associated uprobe. The painful part here is retrieving info from the string of USDT arguments in the ELF note such that we can generate trampoline code to retrieve the probe arguments. Probe arguments can be either constants, register values or dereferences from register values (plus offset). Use bpf_probe_read[_user] for the latter case. Translating from the register names in the USDT argument string is platform-specific, so we use arrays mapping the register names used to the appropriate pt_regs field name, along with an offset (for the aarch64 case where the regs[] array in user_pt_regs is used). Wildcarded pid USDT probes are not yet supported; a specific pid is required. As well as supporting ELF-note defined probes in programs and libraries, this patch supports dynamically-created probes that are created via libstapsdt [1]. libstapsdt allows dynamic languages like python to declare and fire probes by dynamically creating a memfd-based shared library containing ELF notes for the probes. With these changes we can also trace these probes. This is very useful since libstapsdt has python, NodeJS, go and luaJIT bindings. [1] https://github.com/linux-usdt/libstapsdt Signed-off-by: Alan Maguire --- include/dtrace/pid.h | 29 +++ libdtrace/dt_cg.c | 47 ++++ libdtrace/dt_cg.h | 1 + libdtrace/dt_pid.c | 451 +++++++++++++++++++++++++++++++++++++ libdtrace/dt_prov_uprobe.c | 19 +- 5 files changed, 540 insertions(+), 7 deletions(-) diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h index c53e6004..a8e26da4 100644 --- a/include/dtrace/pid.h +++ b/include/dtrace/pid.h @@ -26,6 +26,27 @@ typedef enum pid_probetype { DTPPT_IS_ENABLED } pid_probetype_t; +#define DT_USDT_MAX_ARGS 10 + +enum dt_usdt_arg_type { + DT_USDT_ARG_NONE = 0, + DT_USDT_ARG_CONST, + DT_USDT_ARG_REG, + DT_USDT_ARG_REG_DEREF +}; + +struct dt_usdt_arg { + enum dt_usdt_arg_type ua_type; + int ua_val_sz; + int ua_val_off; + int64_t ua_const_val; + const char *ua_regs_name; /* pt_regs/user_pt_regs */ + const char *ua_regs_field; /* x0/rsp etc */ + int ua_regs_field_off; /* used for array regs[] */ +}; + +typedef struct dt_usdt_arg dt_usdt_arg_t; + typedef struct pid_probespec { pid_probetype_t pps_type; /* probe type */ char *pps_prv; /* provider (without pid) */ @@ -44,6 +65,14 @@ typedef struct pid_probespec { size_t pps_xargvlen; /* (high estimate of) length of array */ int8_t *pps_argmap; /* mapped arg indexes */ + int pps_nuargs; /* number of arg specs in + * pps_uargs + */ + dt_usdt_arg_t pps_uargs[DT_USDT_MAX_ARGS]; + /* USDT ELF note-defined + * provider arguments. + */ + /* * Fields below this point do not apply to underlying probes. */ diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index e7e3a132..2c8f8210 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -651,6 +651,53 @@ dt_cg_tramp_copy_rval_from_regs(dt_pcb_t *pcb) emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), 0)); } +void +dt_cg_tramp_copy_args_from_usdt_spec(dt_pcb_t *pcb, const dt_usdt_arg_t *args) +{ + dtrace_hdl_t *dtp = pcb->pcb_hdl; + dt_irlist_t *dlp = &pcb->pcb_ir; + int reg_val_off, i; + + for (i = 0; i < DT_USDT_MAX_ARGS; i++) { + const dt_usdt_arg_t *arg = &args[i]; + uint_t lbl_ok = dt_irlist_label(dlp); + + switch (arg->ua_type) { + case DT_USDT_ARG_NONE: + return; + case DT_USDT_ARG_CONST: + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), + arg->ua_const_val)); + break; + case DT_USDT_ARG_REG: + case DT_USDT_ARG_REG_DEREF: + reg_val_off = dt_cg_ctf_offsetof(arg->ua_regs_name, + arg->ua_regs_field, NULL, 0); + reg_val_off += arg->ua_regs_field_off; + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, + reg_val_off)); + /* do direct register value copy */ + if (arg->ua_type == DT_USDT_ARG_REG) { + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), + BPF_REG_0)); + break; + } + /* otherwise call bpf_probe_read[_user] to get dereferenced value. + */ + emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_7)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DMST_ARG(i))); + emit(dlp, BPF_MOV_IMM(BPF_REG_2, abs(arg->ua_val_sz))); + emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, arg->ua_val_off)); + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user])); + emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_ok)); + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), 0)); + emitl(dlp, lbl_ok, BPF_NOP()); + break; + } + } +} + static dt_node_t * dt_cg_tramp_var(const char *name) { diff --git a/libdtrace/dt_cg.h b/libdtrace/dt_cg.h index fb26c125..24257f0b 100644 --- a/libdtrace/dt_cg.h +++ b/libdtrace/dt_cg.h @@ -28,6 +28,7 @@ extern void dt_cg_tramp_copy_regs(dt_pcb_t *pcb); extern void dt_cg_tramp_copy_args_from_regs(dt_pcb_t *pcb, int called); extern void dt_cg_tramp_copy_pc_from_regs(dt_pcb_t *pcb); extern void dt_cg_tramp_copy_rval_from_regs(dt_pcb_t *pcb); +extern void dt_cg_tramp_copy_args_from_usdt_spec(dt_pcb_t *pcb, const dt_usdt_arg_t *args); extern void dt_cg_tramp_decl_var(dt_pcb_t *pcb, dt_ident_t *idp); extern void dt_cg_tramp_get_var(dt_pcb_t *pcb, const char *name, int isstore, int reg); diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index 4d53c023..5608e380 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -28,6 +28,8 @@ #if defined(__amd64) #include #endif +#include +#include #include #include @@ -780,6 +782,351 @@ validate_dof_record(const char *path, const dof_parsed_t *parsed, return 1; } +#define SEC_USDT_NOTE ".note.stapsdt" +#define NAME_USDT_NOTE "stapsdt" + +struct pt_regs_info { + const char ua_name[8]; + const char name[8]; + int off; +} pt_regs_info[] = { + +#if defined(__aarch64__) + { "sp", "sp", 0 }, + { "x0", "regs", 0 }, + { "x1", "regs", 1 * sizeof(unsigned long) }, + { "x2", "regs", 2 * sizeof(unsigned long) }, + { "x3", "regs", 3 * sizeof(unsigned long) }, + { "x4", "regs", 4 * sizeof(unsigned long) }, + { "x5", "regs", 5 * sizeof(unsigned long) }, + { "x6", "regs", 6 * sizeof(unsigned long) }, + { "x7", "regs", 7 * sizeof(unsigned long) }, + { "x8", "regs", 8 * sizeof(unsigned long) }, + { "x9", "regs", 9 * sizeof(unsigned long) }, + { "x10", "regs", 10 * sizeof(unsigned long) }, + { "x11", "regs", 11 * sizeof(unsigned long) }, + { "x12", "regs", 12 * sizeof(unsigned long) }, + { "x13", "regs", 13 * sizeof(unsigned long) }, + { "x14", "regs", 14 * sizeof(unsigned long) }, + { "x15", "regs", 15 * sizeof(unsigned long) }, + { "x16", "regs", 16 * sizeof(unsigned long) }, + { "x17", "regs", 17 * sizeof(unsigned long) }, + { "x18", "regs", 18 * sizeof(unsigned long) }, + { "x19", "regs", 19 * sizeof(unsigned long) }, + { "x20", "regs", 20 * sizeof(unsigned long) }, + { "x21", "regs", 21 * sizeof(unsigned long) }, + { "x222", "regs", 22 * sizeof(unsigned long) }, + { "x23", "regs", 23 * sizeof(unsigned long) }, + { "x24", "regs", 24 * sizeof(unsigned long) }, + { "x25", "regs", 25 * sizeof(unsigned long) }, + { "x26", "regs", 26 * sizeof(unsigned long) }, + { "x27", "regs", 27 * sizeof(unsigned long) }, + { "x28", "regs", 28 * sizeof(unsigned long) }, + { "x29", "regs", 29 * sizeof(unsigned long) }, + { "x30", "regs", 30 * sizeof(unsigned long) }, + { "x31", "regs", 31 * sizeof(unsigned long) } +#else + { "rip", "ip", 0 }, + { "eip", "ip", 0 }, + { "rax", "ax", 0 }, + { "eax", "ax", 0 }, + { "ax", "ax", 0 }, + { "al", "ax", 0 }, + { "rbx", "bx", 0 }, + { "ebx", "bx", 0 }, + { "bx", "bx", 0 }, + { "bl", "bx", 0 }, + { "rcx", "cx", 0 }, + { "ecx", "cx", 0 }, + { "cx", "cx", 0 }, + { "cl", "cx", 0 }, + { "rdx", "dx", 0 }, + { "edx", "dx", 0 }, + { "dx", "dx", 0 }, + { "dl", "dx", 0 }, + { "rsi", "si", 0 }, + { "esi", "si", 0 }, + { "si", "si", 0 }, + { "sil", "si", 0 }, + { "rdi", "di", 0 }, + { "edi", "di", 0 }, + { "di", "di", 0 }, + { "dil", "di", 0 }, + { "rbp", "bp", 0 }, + { "ebp", "bp", 0 }, + { "bp", "bp", 0 }, + { "bpl", "bp", 0 }, + { "rsp", "sp", 0 }, + { "esp", "sp", 0 }, + { "sp", "sp", 0 }, + { "spl", "sp", 0 } +#endif +}; + +static void dt_usdt_note_print_arg(dt_usdt_arg_t *a) +{ + switch (a->ua_type) { + case DT_USDT_ARG_NONE: + return; + case DT_USDT_ARG_CONST: + dt_dprintf("CONST %ld\n", a->ua_const_val); + break; + case DT_USDT_ARG_REG_DEREF: + dt_dprintf("REG DEREF (%s.%s + %d) + %d\n", + a->ua_regs_name, a->ua_regs_field, + a->ua_regs_field_off, a->ua_val_off); + break; + case DT_USDT_ARG_REG: + dt_dprintf("REG VALUE (%s.%s + %d)\n", + a->ua_regs_name, a->ua_regs_field, + a->ua_regs_field_off); + break; + } +} + +/* retrieve arguments; space-separated string of arguments of form: + * [-]numbytes@[optional_offset_from(]%regname[)] + * + * for example: + * + * -4 at -4(%rbp) means memory dereference of 4 bytes, 4 bytes + * offset from %rbp value. + * 8@(%rax) means memory dereference of 8 bytes from + * rax register value (no offset) + * 8@%rax means 8 bytes from rax register value (no deref). + * 4@$32 means 4 byte constant value 32 + */ +static int dt_usdt_note_parse_arg(char **argstr, struct dt_usdt_arg *a) +{ + char *arg = *argstr; + char reg[8] = {}; + int len; + + if (sscanf(arg, +#if defined(__aarch64__) + " %d @ \[ %[a-z0-9] , %d ] %n", + &a->ua_val_sz, reg, &a->ua_val_off, &len) +#else + " %d @ %d ( %%%8[^)] ) %n", + &a->ua_val_sz, &a->ua_val_off, reg, &len) +#endif + == 3) { + a->ua_type = DT_USDT_ARG_REG_DEREF; + } else if (sscanf(arg, +#if defined(__aarch64__) + " %d @ \[ %7[a-z0-9] ] %n", &a->ua_val_sz, reg, &len) +#else + " %d @ ( %%%7[^)] ) %n", &a->ua_val_sz, reg, &len) +#endif + == 2) { + a->ua_type = DT_USDT_ARG_REG_DEREF; + } else if (sscanf(arg, +#if defined(__x86_64__) + " %d @ $%ld %n", &a->ua_val_sz, &a->ua_const_val, &len) +#else + " %d @ %ld %n", &a->ua_val_sz, &a->ua_const_val, &len) +#endif + == 2) { + a->ua_type = DT_USDT_ARG_CONST; + } else if (sscanf(arg, +#if defined(__aarch64__) + " %d @ %7[a-z0-9] %n", &a->ua_val_sz, reg, &len) +#else + " %d @ %%%7s %n", &a->ua_val_sz, reg, &len) +#endif + == 2) { + a->ua_type = DT_USDT_ARG_REG; + } else { + return -1; + } + if (strlen(reg) > 0) { + int i; + +#if defined(__aarch64__) + a->ua_regs_name = "struct user_pt_regs"; +#else + a->ua_regs_name = "struct pt_regs"; +#endif + for (i = 0; i < ARRAY_SIZE(pt_regs_info); i++) { + if (strcmp(pt_regs_info[i].ua_name, reg)) + continue; + a->ua_regs_field = pt_regs_info[i].name; + a->ua_regs_field_off = pt_regs_info[i].off; + } + } + *argstr += len; + return 0; +} + +static int dt_usdt_notes_parse(dtrace_hdl_t *dtp, dt_proc_t *dpr, + dtrace_probedesc_t *pdp, dt_pcb_t *pcb, + const dt_provider_t *pvp, const char *path, + unsigned long base_addr) +{ + Elf *elf; + Elf_Scn *scn = NULL; + GElf_Shdr shdr; + GElf_Nhdr nhdr; + size_t shstrndx, noff, doff, off, n; + Elf_Data *data; + int i, ret = 0; + int fd = -1; + + dt_dprintf("Scanning for USDT probes in ELF notes in '%s' (pid %i) matching %s:%s:%s\n", + path, dpr->dpr_pid, pdp->mod, pdp->fun, pdp->prb); + + fd = open(path, O_RDONLY); + if (fd < 0) { + dt_pid_error(dtp, pcb, dpr, D_PROC_USDT, + "Cannot open %s: %s\n", + path, strerror(errno)); + return -1; + } + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); // ELF_C_READ ? + assert(elf_kind(elf) == ELF_K_ELF); + elf_getshdrstrndx(elf, &shstrndx); + + while (1) { + char *secname; + + scn = elf_nextscn(elf, scn); + if (scn == NULL) { + /* no ELF notes found, not an error */ + return 0; + } + assert(gelf_getshdr(scn, &shdr) != NULL); + + secname = elf_strptr(elf, shstrndx, shdr.sh_name); + if (strcmp(secname, SEC_USDT_NOTE) == 0 && + shdr.sh_type == SHT_NOTE) + break; + } + /* No ELF notes, just bail. */ + if (scn == NULL) + goto out; + data = elf_getdata(scn, 0); + for (off = 0; + (off = gelf_getnote(data, off, &nhdr, &noff, &doff)) > 0;) { + pid_probespec_t psp = {0}; + char *prv, *prb; + const char *fun; + char mod[PATH_MAX]; + char *dbuf = (char *)data->d_buf; + long *addrs = data->d_buf + doff; /* 3 addrs are loc/base/semaphore */ + GElf_Sym sym; + const prmap_t *pmp; + int nargs = 0; + + if (strncmp(dbuf + noff, NAME_USDT_NOTE, nhdr.n_namesz) != 0) + continue; + prv = dbuf + doff + (3*sizeof(long)); + /* ensure prv/prb is null-terminated */ + assert(strlen(prv) < nhdr.n_descsz); + prb = prv + strlen(prv) + 1; + assert(strlen(prb) < nhdr.n_descsz); + if (strncmp(pdp->prv, prv, strlen(prv)) != 0) + continue; + if (strcmp(pdp->prb, "*") != 0 && strcmp(pdp->prb, prb) != 0) + continue; + /* retrieve arguments; space-separated string of arguments + * in form: + * [-]numbytes@[optional_offset_from(]%regname[)] + * + * for example: + * + * -4 at -4(%rbp) means memory dereference of 4 bytes, 4 bytes + * offset from %rbp value. + * 8@(%rax) means memory dereference of 8 bytes from + * rax register value (no offset) + * 8@%rax means 8 bytes from rax register value (no deref). + * 4@$32 means 4 byte constant value 32 + */ + if (prb + strlen(prb) + 1 < dbuf + doff + nhdr.n_descsz) { + char *argstr = prb + strlen(prb) + 1; + + while (dt_usdt_note_parse_arg(&argstr, + &psp.pps_uargs[nargs]) == 0 && + nargs < DT_USDT_MAX_ARGS) { + dt_usdt_note_print_arg(&psp.pps_uargs[nargs]); + nargs++; + } + psp.pps_nuargs = nargs; + + } + dt_dprintf("found ELF note for provider '%s', probe '%s' in %s, loc 0x%lx, base 0x%lx, nargs %d\n", + prv, prb, path, addrs[0], addrs[1], nargs); + psp.pps_type = DTPPT_USDT; + psp.pps_prv = prv; + if (dt_Pobjname(dtp, dpr->dpr_pid, base_addr + addrs[0], mod, + sizeof(mod)) == NULL) { + dt_dprintf("cannot determine mod name for 0x%lx\n", addrs[0]); + mod[0] = '\0'; + } + psp.pps_mod = basename(mod); + psp.pps_prb = prb; + if (elf_getphdrnum(elf, &n)) + continue; + for (i = 0; i < n; i++) { + GElf_Phdr phdr; + + if (!gelf_getphdr(elf, i, &phdr)) + break; + + if (addrs[0] < phdr.p_vaddr || + addrs[0] > phdr.p_vaddr + phdr.p_memsz) + continue; + if (base_addr) + psp.pps_off = addrs[0]; + else + psp.pps_off = addrs[0] - phdr.p_vaddr + phdr.p_offset; + break; + } + if (!psp.pps_off) + continue; + psp.pps_nameoff = 0; + + pmp = Paddr_to_map(dpr->dpr_proc, base_addr + addrs[0]); + if (!pmp) { + dt_dprintf("%i: cannot determine 0x%lx's mapping\n", + Pgetpid(dpr->dpr_proc), psp.pps_off); + continue; + } + psp.pps_fn = Pmap_mapfile_name(dpr->dpr_proc, pmp); + if (psp.pps_fn == NULL) { + dt_pid_error(dtp, pcb, dpr, D_PROC_USDT, + "Cannot get name of mapping containing probe %s for pid %d\n", + psp.pps_prb, dpr->dpr_pid); + ret = -1; + break; + } + if (dt_Plookup_by_addr(dtp, dpr->dpr_pid, base_addr + addrs[0], + &fun, &sym) == 0) + psp.pps_fun = (char *)fun; + else + psp.pps_fun = ""; + psp.pps_dev = pmp->pr_dev; + psp.pps_inum = pmp->pr_inum; + psp.pps_pid = dpr->dpr_pid; + psp.pps_nameoff = 0; + + dt_dprintf("providing %s:%s:%s:%s for pid %d at addr 0x%lx\n", psp.pps_prv, + psp.pps_mod, psp.pps_fun, psp.pps_prb, psp.pps_pid, + base_addr + addrs[0]); + if (pvp->impl->provide_probe(dtp, &psp) < 0) { + dt_pid_error(dtp, pcb, dpr, D_PROC_USDT, + "failed to instantiate probe %s for pid %d: %s", + psp.pps_prb, psp.pps_pid, + dtrace_errmsg(dtp, dtrace_errno(dtp))); + ret = -1; + } + free(psp.pps_fn); + if (ret == -1) + break; + } +out: + close(fd); + return ret; +} /* * Create underlying probes relating to the probespec passed on input. @@ -1202,6 +1549,108 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *p return err; } +static int +dt_pid_create_usdt_notes_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, + dt_pcb_t *pcb) +{ + const char *pidstr = &pdp->prv[strlen(pdp->prv)]; + const dt_provider_t *pvp; + char path[PATH_MAX + 1]; + dt_proc_t *dpr = NULL; + FILE *fp = NULL; + pid_t pid = 0; + int err; + + /* only specific pids are support for ELF notes for now... */ + while (isdigit(*(pidstr - 1))) + pidstr--; + if (strlen(pidstr) > 0) + pid = atoll(pidstr); + if (!Pexists(pid)) + return 0; + pvp = dt_provider_lookup(dtp, "usdt"); + assert(pvp != NULL); + + if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING | + DTRACE_PROC_SHORTLIVED) < 0) { + dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, + "failed to grab process %d", + (int)pid); + return 1; + } + dpr = dt_proc_lookup(dtp, pid); + assert(dpr != NULL); + snprintf(path, sizeof(path), "/proc/%d/exe", dpr->dpr_pid); + err = dt_usdt_notes_parse(dtp, dpr, pdp, pcb, pvp, path, 0); + if (err) + goto out; + + snprintf(path, sizeof(path), "/proc/%d/maps", pid); + + fp = fopen(path, "r"); + if (!fp) { + dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, + "no /proc/%d/maps found", (int)pid); + err = 1; + goto out; + } + do { + long addr_start, addr_end, file_offset; + long dev_major, dev_minor; + unsigned long inode; + char name[PATH_MAX + 1]; + char perm[5]; + + + if (fscanf(fp, + "%lx-%lx %4s %lx %lx:%lx %lu %[^\n]", + &addr_start, &addr_end, perm, &file_offset, + &dev_major, &dev_minor, &inode, name) != 8 || + !strchr(perm, 'x') || strchr(name, '[') != NULL) + continue; + /* libstapsdt uses an memfd-based library to dynamically create + * stapsdt notes for dynamic languages like python; we need + * the associated /proc//fds/ fd to read these notes. + */ + if (strncmp(name, "/memfd:", strlen("/memfd:")) == 0) { + DIR *d; + struct dirent *dirent; + char *deleted; + + deleted = strstr(name, " (deleted)"); + *deleted = '\0'; + snprintf(path, sizeof(path), "/proc/%d/fd", pid); + d = opendir(path); + if (d == NULL) + continue; + while ((dirent = readdir(d)) != NULL) { + struct stat s; + + snprintf(path, sizeof(path), "/proc/%d/fd/%s", + pid, dirent->d_name); + if (stat(path, &s) != 0 || s.st_ino != inode) + continue; + if (dt_usdt_notes_parse(dtp, dpr, pdp, pcb, pvp, + path, addr_start) != 0) { + err = 1; + goto out; + } + } + } else { + if (dt_usdt_notes_parse(dtp, dpr, pdp, pcb, pvp, name, addr_start) != 0) { + err = 1; + goto out; + } + } + } while (!feof(fp)); +out: + if (fp) + fclose(fp); + dt_pid_fix_mod(NULL, pdp, dtp, dpr->dpr_pid); + dt_proc_release_unlock(dtp, pid); + return err; +} + int dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb) { @@ -1273,6 +1722,8 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t * free(globpat); globfree(&globbuf); + err = dt_pid_create_usdt_notes_probes(pdp, dtp, pcb); + /* If no errors, report success. */ if (err == 0) return 0; diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index 78d9aed6..08b60b44 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -51,6 +51,7 @@ static const char prvname[] = "uprobe"; #define PP_IS_ENABLED 0x4 #define PP_IS_USDT 0x8 #define PP_IS_MAPPED 0x10 +#define PP_IS_USDT_NOTE 0x20 typedef struct dt_uprobe { dev_t dev; @@ -58,6 +59,7 @@ typedef struct dt_uprobe { char *fn; uint64_t off; int flags; + dt_usdt_arg_t uargs[DT_USDT_MAX_ARGS]; tp_probe_t *tp; int argc; /* number of args */ dt_argdesc_t *args; /* args array (points into argvbuf) */ @@ -651,7 +653,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, pd.prb = prb; dt_dprintf("Providing underlying probe %s:%s:%s:%s @ %lx\n", psp->pps_prv, - psp->pps_mod, psp->pps_fn, psp->pps_prb, psp->pps_off); + psp->pps_mod, psp->pps_fun, psp->pps_prb, psp->pps_off); uprp = dt_probe_lookup(dtp, &pd); if (uprp == NULL) { dt_provider_t *pvp; @@ -671,6 +673,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, upp->off = psp->pps_off; upp->fn = strdup(psp->pps_fn); upp->tp = dt_tp_alloc(dtp); + memcpy(&upp->uargs, psp->pps_uargs, sizeof(upp->uargs)); if (upp->tp == NULL) goto fail; @@ -702,11 +705,11 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, break; case DTPPT_USDT: upp->flags |= PP_IS_USDT; + if (psp->pps_nuargs) + upp->flags |= PP_IS_USDT_NOTE; + break; + default: break; - default: ; - /* - * No flags needed for other types. - */ } return uprp; @@ -973,8 +976,10 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) /* 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); + else if (upp->flags & PP_IS_USDT_NOTE) + dt_cg_tramp_copy_args_from_usdt_spec(pcb, upp->uargs); + else + dt_cg_tramp_copy_args_from_regs(pcb, 0); /* * Apply arg mappings, if needed. -- 2.43.5 From alan.maguire at oracle.com Wed Jan 29 14:43:59 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Wed, 29 Jan 2025 14:43:59 +0000 Subject: [DTrace-devel] [PATCH 2/4] selftests/usdt: add test for USDT note-defined probe firing, args In-Reply-To: <20250129144401.505186-1-alan.maguire@oracle.com> References: <20250129144401.505186-1-alan.maguire@oracle.com> Message-ID: <20250129144401.505186-3-alan.maguire@oracle.com> Add test identical to the args tests to verify probe firing and arg retrieval work for USDT notes-defined DTRACE_PROBEn() probes. Need a copy of the sdt.h file which is public domain, so add it in the test directory. Signed-off-by: Alan Maguire --- test/unittest/usdt/sdt_notes.h | 504 +++++++++++++++++++++++++++ test/unittest/usdt/tst.usdt-notes.r | 14 + test/unittest/usdt/tst.usdt-notes.sh | 121 +++++++ 3 files changed, 639 insertions(+) create mode 100644 test/unittest/usdt/sdt_notes.h create mode 100644 test/unittest/usdt/tst.usdt-notes.r create mode 100755 test/unittest/usdt/tst.usdt-notes.sh diff --git a/test/unittest/usdt/sdt_notes.h b/test/unittest/usdt/sdt_notes.h new file mode 100644 index 00000000..ec5423e2 --- /dev/null +++ b/test/unittest/usdt/sdt_notes.h @@ -0,0 +1,504 @@ +/* - Systemtap static probe definition macros. + + This file is dedicated to the public domain, pursuant to CC0 + (https://creativecommons.org/publicdomain/zero/1.0/) +*/ + +#ifndef _SYS_SDT_H +#define _SYS_SDT_H 1 + +/* + This file defines a family of macros + + STAP_PROBEn(op1, ..., opn) + + that emit a nop into the instruction stream, and some data into an auxiliary + note section. The data in the note section describes the operands, in terms + of size and location. Each location is encoded as assembler operand string. + Consumer tools such as gdb or systemtap insert breakpoints on top of + the nop, and decode the location operand-strings, like an assembler, + to find the values being passed. + + The operand strings are selected by the compiler for each operand. + They are constrained by gcc inline-assembler codes. The default is: + + #define STAP_SDT_ARG_CONSTRAINT nor + + This is a good default if the operands tend to be integral and + moderate in number (smaller than number of registers). In other + cases, the compiler may report "'asm' requires impossible reload" or + similar. In this case, consider simplifying the macro call (fewer + and simpler operands), reduce optimization, or override the default + constraints string via: + + #define STAP_SDT_ARG_CONSTRAINT g + #include + + See also: + https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation + https://gcc.gnu.org/onlinedocs/gcc/Constraints.html + */ + + + +#ifdef __ASSEMBLER__ +# define _SDT_PROBE(provider, name, n, arglist) \ + _SDT_ASM_BODY(provider, name, _SDT_ASM_SUBSTR_1, (_SDT_DEPAREN_##n arglist)) \ + _SDT_ASM_BASE +# define _SDT_ASM_1(x) x; +# define _SDT_ASM_2(a, b) a,b; +# define _SDT_ASM_3(a, b, c) a,b,c; +# define _SDT_ASM_5(a, b, c, d, e) a,b,c,d,e; +# define _SDT_ASM_STRING_1(x) .asciz #x; +# define _SDT_ASM_SUBSTR_1(x) .ascii #x; +# define _SDT_DEPAREN_0() /* empty */ +# define _SDT_DEPAREN_1(a) a +# define _SDT_DEPAREN_2(a,b) a b +# define _SDT_DEPAREN_3(a,b,c) a b c +# define _SDT_DEPAREN_4(a,b,c,d) a b c d +# define _SDT_DEPAREN_5(a,b,c,d,e) a b c d e +# define _SDT_DEPAREN_6(a,b,c,d,e,f) a b c d e f +# define _SDT_DEPAREN_7(a,b,c,d,e,f,g) a b c d e f g +# define _SDT_DEPAREN_8(a,b,c,d,e,f,g,h) a b c d e f g h +# define _SDT_DEPAREN_9(a,b,c,d,e,f,g,h,i) a b c d e f g h i +# define _SDT_DEPAREN_10(a,b,c,d,e,f,g,h,i,j) a b c d e f g h i j +# define _SDT_DEPAREN_11(a,b,c,d,e,f,g,h,i,j,k) a b c d e f g h i j k +# define _SDT_DEPAREN_12(a,b,c,d,e,f,g,h,i,j,k,l) a b c d e f g h i j k l +#else +#if defined _SDT_HAS_SEMAPHORES +#define _SDT_NOTE_SEMAPHORE_USE(provider, name) \ + __asm__ __volatile__ ("" :: "m" (provider##_##name##_semaphore)); +#else +#define _SDT_NOTE_SEMAPHORE_USE(provider, name) +#endif + +# define _SDT_PROBE(provider, name, n, arglist) \ + do { \ + _SDT_NOTE_SEMAPHORE_USE(provider, name); \ + __asm__ __volatile__ (_SDT_ASM_BODY(provider, name, _SDT_ASM_ARGS, (n)) \ + :: _SDT_ASM_OPERANDS_##n arglist); \ + __asm__ __volatile__ (_SDT_ASM_BASE); \ + } while (0) +# define _SDT_S(x) #x +# define _SDT_ASM_1(x) _SDT_S(x) "\n" +# define _SDT_ASM_2(a, b) _SDT_S(a) "," _SDT_S(b) "\n" +# define _SDT_ASM_3(a, b, c) _SDT_S(a) "," _SDT_S(b) "," \ + _SDT_S(c) "\n" +# define _SDT_ASM_5(a, b, c, d, e) _SDT_S(a) "," _SDT_S(b) "," \ + _SDT_S(c) "," _SDT_S(d) "," \ + _SDT_S(e) "\n" +# define _SDT_ASM_ARGS(n) _SDT_ASM_TEMPLATE_##n +# define _SDT_ASM_STRING_1(x) _SDT_ASM_1(.asciz #x) +# define _SDT_ASM_SUBSTR_1(x) _SDT_ASM_1(.ascii #x) + +# define _SDT_ARGFMT(no) _SDT_ASM_1(_SDT_SIGN %n[_SDT_S##no]) \ + _SDT_ASM_1(_SDT_SIZE %n[_SDT_S##no]) \ + _SDT_ASM_1(_SDT_TYPE %n[_SDT_S##no]) \ + _SDT_ASM_SUBSTR(_SDT_ARGTMPL(_SDT_A##no)) + + +# ifndef STAP_SDT_ARG_CONSTRAINT +# if defined __powerpc__ +# define STAP_SDT_ARG_CONSTRAINT nZr +# elif defined __arm__ +# define STAP_SDT_ARG_CONSTRAINT g +# else +# define STAP_SDT_ARG_CONSTRAINT nor +# endif +# endif + +# define _SDT_STRINGIFY(x) #x +# define _SDT_ARG_CONSTRAINT_STRING(x) _SDT_STRINGIFY(x) +/* _SDT_S encodes the size and type as 0xSSTT which is decoded by the assembler + macros _SDT_SIZE and _SDT_TYPE */ +# define _SDT_ARG(n, x) \ + [_SDT_S##n] "n" ((_SDT_ARGSIGNED (x) ? (int)-1 : 1) * (-(((int) _SDT_ARGSIZE (x)) << 8) + (-(0x7f & __builtin_classify_type (x))))), \ + [_SDT_A##n] _SDT_ARG_CONSTRAINT_STRING (STAP_SDT_ARG_CONSTRAINT) (_SDT_ARGVAL (x)) +#endif +#define _SDT_ASM_STRING(x) _SDT_ASM_STRING_1(x) +#define _SDT_ASM_SUBSTR(x) _SDT_ASM_SUBSTR_1(x) + +#define _SDT_ARGARRAY(x) (__builtin_classify_type (x) == 14 \ + || __builtin_classify_type (x) == 5) + +#ifdef __cplusplus +# define _SDT_ARGSIGNED(x) (!_SDT_ARGARRAY (x) \ + && __sdt_type<__typeof (x)>::__sdt_signed) +# define _SDT_ARGSIZE(x) (_SDT_ARGARRAY (x) \ + ? sizeof (void *) : sizeof (x)) +# define _SDT_ARGVAL(x) (x) + +# include + +template +struct __sdt_type +{ + static const bool __sdt_signed = false; +}; + +#define __SDT_ALWAYS_SIGNED(T) \ +template<> struct __sdt_type { static const bool __sdt_signed = true; }; +#define __SDT_COND_SIGNED(T,CT) \ +template<> struct __sdt_type { static const bool __sdt_signed = ((CT)(-1) < 1); }; +__SDT_ALWAYS_SIGNED(signed char) +__SDT_ALWAYS_SIGNED(short) +__SDT_ALWAYS_SIGNED(int) +__SDT_ALWAYS_SIGNED(long) +__SDT_ALWAYS_SIGNED(long long) +__SDT_ALWAYS_SIGNED(volatile signed char) +__SDT_ALWAYS_SIGNED(volatile short) +__SDT_ALWAYS_SIGNED(volatile int) +__SDT_ALWAYS_SIGNED(volatile long) +__SDT_ALWAYS_SIGNED(volatile long long) +__SDT_ALWAYS_SIGNED(const signed char) +__SDT_ALWAYS_SIGNED(const short) +__SDT_ALWAYS_SIGNED(const int) +__SDT_ALWAYS_SIGNED(const long) +__SDT_ALWAYS_SIGNED(const long long) +__SDT_ALWAYS_SIGNED(const volatile signed char) +__SDT_ALWAYS_SIGNED(const volatile short) +__SDT_ALWAYS_SIGNED(const volatile int) +__SDT_ALWAYS_SIGNED(const volatile long) +__SDT_ALWAYS_SIGNED(const volatile long long) +__SDT_COND_SIGNED(char, char) +__SDT_COND_SIGNED(wchar_t, wchar_t) +__SDT_COND_SIGNED(volatile char, char) +__SDT_COND_SIGNED(volatile wchar_t, wchar_t) +__SDT_COND_SIGNED(const char, char) +__SDT_COND_SIGNED(const wchar_t, wchar_t) +__SDT_COND_SIGNED(const volatile char, char) +__SDT_COND_SIGNED(const volatile wchar_t, wchar_t) +#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) +/* __SDT_COND_SIGNED(char16_t) */ +/* __SDT_COND_SIGNED(char32_t) */ +#endif + +template +struct __sdt_type<__sdt_E[]> : public __sdt_type<__sdt_E *> {}; + +template +struct __sdt_type<__sdt_E[__sdt_N]> : public __sdt_type<__sdt_E *> {}; + +#elif !defined(__ASSEMBLER__) +__extension__ extern unsigned long long __sdt_unsp; +# define _SDT_ARGINTTYPE(x) \ + __typeof (__builtin_choose_expr (((__builtin_classify_type (x) \ + + 3) & -4) == 4, (x), 0U)) +# define _SDT_ARGSIGNED(x) \ + (!__extension__ \ + (__builtin_constant_p ((((unsigned long long) \ + (_SDT_ARGINTTYPE (x)) __sdt_unsp) \ + & ((unsigned long long)1 << (sizeof (unsigned long long) \ + * __CHAR_BIT__ - 1))) == 0) \ + || (_SDT_ARGINTTYPE (x)) -1 > (_SDT_ARGINTTYPE (x)) 0)) +# define _SDT_ARGSIZE(x) \ + (_SDT_ARGARRAY (x) ? sizeof (void *) : sizeof (x)) +# define _SDT_ARGVAL(x) (x) +#endif + +#if defined __powerpc__ || defined __powerpc64__ +# define _SDT_ARGTMPL(id) %I[id]%[id] +#elif defined __i386__ +# define _SDT_ARGTMPL(id) %k[id] /* gcc.gnu.org/PR80115 sourceware.org/PR24541 */ +#else +# define _SDT_ARGTMPL(id) %[id] +#endif + +/* NB: gdb PR24541 highlighted an unspecified corner of the sdt.h + operand note format. + + The named register may be a longer or shorter (!) alias for the + storage where the value in question is found. For example, on + i386, 64-bit value may be put in register pairs, and the register + name stored would identify just one of them. Previously, gcc was + asked to emit the %w[id] (16-bit alias of some registers holding + operands), even when a wider 32-bit value was used. + + Bottom line: the byte-width given before the @ sign governs. If + there is a mismatch between that width and that of the named + register, then a sys/sdt.h note consumer may need to employ + architecture-specific heuristics to figure out where the compiler + has actually put the complete value. +*/ + +#ifdef __LP64__ +# define _SDT_ASM_ADDR .8byte +#else +# define _SDT_ASM_ADDR .4byte +#endif + +/* The ia64 and s390 nop instructions take an argument. */ +#if defined(__ia64__) || defined(__s390__) || defined(__s390x__) +#define _SDT_NOP nop 0 +#else +#define _SDT_NOP nop +#endif + +#define _SDT_NOTE_NAME "stapsdt" +#define _SDT_NOTE_TYPE 3 + +# define _SDT_ASM_AUTOGROUP "?" + +#define _SDT_DEF_MACROS \ + _SDT_ASM_1(.altmacro) \ + _SDT_ASM_1(.macro _SDT_SIGN x) \ + _SDT_ASM_3(.pushsection .note.stapsdt,"","note") \ + _SDT_ASM_1(.iflt \\x) \ + _SDT_ASM_1(.ascii "-") \ + _SDT_ASM_1(.endif) \ + _SDT_ASM_1(.popsection) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_SIZE_ x) \ + _SDT_ASM_3(.pushsection .note.stapsdt,"","note") \ + _SDT_ASM_1(.ascii "\x") \ + _SDT_ASM_1(.popsection) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_SIZE x) \ + _SDT_ASM_1(_SDT_SIZE_ %%((-(-\\x*((-\\x>0)-(-\\x<0))))>>8)) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_TYPE_ x) \ + _SDT_ASM_3(.pushsection .note.stapsdt,"","note") \ + _SDT_ASM_2(.ifc 8,\\x) \ + _SDT_ASM_1(.ascii "f") \ + _SDT_ASM_1(.endif) \ + _SDT_ASM_1(.ascii "@") \ + _SDT_ASM_1(.popsection) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_TYPE x) \ + _SDT_ASM_1(_SDT_TYPE_ %%((\\x)&(0xff))) \ + _SDT_ASM_1(.endm) + +#define _SDT_UNDEF_MACROS \ + _SDT_ASM_1(.purgem _SDT_SIGN) \ + _SDT_ASM_1(.purgem _SDT_SIZE_) \ + _SDT_ASM_1(.purgem _SDT_SIZE) \ + _SDT_ASM_1(.purgem _SDT_TYPE_) \ + _SDT_ASM_1(.purgem _SDT_TYPE) + +#define _SDT_ASM_BODY(provider, name, pack_args, args, ...) \ + _SDT_DEF_MACROS \ + _SDT_ASM_1(990: _SDT_NOP) \ + _SDT_ASM_3( .pushsection .note.stapsdt,_SDT_ASM_AUTOGROUP,"note") \ + _SDT_ASM_1( .balign 4) \ + _SDT_ASM_3( .4byte 992f-991f, 994f-993f, _SDT_NOTE_TYPE) \ + _SDT_ASM_1(991: .asciz _SDT_NOTE_NAME) \ + _SDT_ASM_1(992: .balign 4) \ + _SDT_ASM_1(993: _SDT_ASM_ADDR 990b) \ + _SDT_ASM_1( _SDT_ASM_ADDR _.stapsdt.base) \ + _SDT_SEMAPHORE(provider,name) \ + _SDT_ASM_STRING(provider) \ + _SDT_ASM_STRING(name) \ + pack_args args \ + _SDT_ASM_SUBSTR(\x00) \ + _SDT_UNDEF_MACROS \ + _SDT_ASM_1(994: .balign 4) \ + _SDT_ASM_1( .popsection) + +#define _SDT_ASM_BASE \ + _SDT_ASM_1(.ifndef _.stapsdt.base) \ + _SDT_ASM_5( .pushsection .stapsdt.base,"aG","progbits", \ + .stapsdt.base,comdat) \ + _SDT_ASM_1( .weak _.stapsdt.base) \ + _SDT_ASM_1( .hidden _.stapsdt.base) \ + _SDT_ASM_1( _.stapsdt.base: .space 1) \ + _SDT_ASM_2( .size _.stapsdt.base, 1) \ + _SDT_ASM_1( .popsection) \ + _SDT_ASM_1(.endif) + +#if defined _SDT_HAS_SEMAPHORES +#define _SDT_SEMAPHORE(p,n) \ + _SDT_ASM_1( _SDT_ASM_ADDR p##_##n##_semaphore) +#else +#define _SDT_SEMAPHORE(p,n) _SDT_ASM_1( _SDT_ASM_ADDR 0) +#endif + +#define _SDT_ASM_BLANK _SDT_ASM_SUBSTR(\x20) +#define _SDT_ASM_TEMPLATE_0 /* no arguments */ +#define _SDT_ASM_TEMPLATE_1 _SDT_ARGFMT(1) +#define _SDT_ASM_TEMPLATE_2 _SDT_ASM_TEMPLATE_1 _SDT_ASM_BLANK _SDT_ARGFMT(2) +#define _SDT_ASM_TEMPLATE_3 _SDT_ASM_TEMPLATE_2 _SDT_ASM_BLANK _SDT_ARGFMT(3) +#define _SDT_ASM_TEMPLATE_4 _SDT_ASM_TEMPLATE_3 _SDT_ASM_BLANK _SDT_ARGFMT(4) +#define _SDT_ASM_TEMPLATE_5 _SDT_ASM_TEMPLATE_4 _SDT_ASM_BLANK _SDT_ARGFMT(5) +#define _SDT_ASM_TEMPLATE_6 _SDT_ASM_TEMPLATE_5 _SDT_ASM_BLANK _SDT_ARGFMT(6) +#define _SDT_ASM_TEMPLATE_7 _SDT_ASM_TEMPLATE_6 _SDT_ASM_BLANK _SDT_ARGFMT(7) +#define _SDT_ASM_TEMPLATE_8 _SDT_ASM_TEMPLATE_7 _SDT_ASM_BLANK _SDT_ARGFMT(8) +#define _SDT_ASM_TEMPLATE_9 _SDT_ASM_TEMPLATE_8 _SDT_ASM_BLANK _SDT_ARGFMT(9) +#define _SDT_ASM_TEMPLATE_10 _SDT_ASM_TEMPLATE_9 _SDT_ASM_BLANK _SDT_ARGFMT(10) +#define _SDT_ASM_TEMPLATE_11 _SDT_ASM_TEMPLATE_10 _SDT_ASM_BLANK _SDT_ARGFMT(11) +#define _SDT_ASM_TEMPLATE_12 _SDT_ASM_TEMPLATE_11 _SDT_ASM_BLANK _SDT_ARGFMT(12) +#define _SDT_ASM_OPERANDS_0() [__sdt_dummy] "g" (0) +#define _SDT_ASM_OPERANDS_1(arg1) _SDT_ARG(1, arg1) +#define _SDT_ASM_OPERANDS_2(arg1, arg2) \ + _SDT_ASM_OPERANDS_1(arg1), _SDT_ARG(2, arg2) +#define _SDT_ASM_OPERANDS_3(arg1, arg2, arg3) \ + _SDT_ASM_OPERANDS_2(arg1, arg2), _SDT_ARG(3, arg3) +#define _SDT_ASM_OPERANDS_4(arg1, arg2, arg3, arg4) \ + _SDT_ASM_OPERANDS_3(arg1, arg2, arg3), _SDT_ARG(4, arg4) +#define _SDT_ASM_OPERANDS_5(arg1, arg2, arg3, arg4, arg5) \ + _SDT_ASM_OPERANDS_4(arg1, arg2, arg3, arg4), _SDT_ARG(5, arg5) +#define _SDT_ASM_OPERANDS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ + _SDT_ASM_OPERANDS_5(arg1, arg2, arg3, arg4, arg5), _SDT_ARG(6, arg6) +#define _SDT_ASM_OPERANDS_7(arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + _SDT_ASM_OPERANDS_6(arg1, arg2, arg3, arg4, arg5, arg6), _SDT_ARG(7, arg7) +#define _SDT_ASM_OPERANDS_8(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ + _SDT_ASM_OPERANDS_7(arg1, arg2, arg3, arg4, arg5, arg6, arg7), \ + _SDT_ARG(8, arg8) +#define _SDT_ASM_OPERANDS_9(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) \ + _SDT_ASM_OPERANDS_8(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), \ + _SDT_ARG(9, arg9) +#define _SDT_ASM_OPERANDS_10(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) \ + _SDT_ASM_OPERANDS_9(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), \ + _SDT_ARG(10, arg10) +#define _SDT_ASM_OPERANDS_11(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11) \ + _SDT_ASM_OPERANDS_10(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10), \ + _SDT_ARG(11, arg11) +#define _SDT_ASM_OPERANDS_12(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12) \ + _SDT_ASM_OPERANDS_11(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11), \ + _SDT_ARG(12, arg12) + +/* These macros can be used in C, C++, or assembly code. + In assembly code the arguments should use normal assembly operand syntax. */ + +#define STAP_PROBE(provider, name) \ + _SDT_PROBE(provider, name, 0, ()) +#define STAP_PROBE1(provider, name, arg1) \ + _SDT_PROBE(provider, name, 1, (arg1)) +#define STAP_PROBE2(provider, name, arg1, arg2) \ + _SDT_PROBE(provider, name, 2, (arg1, arg2)) +#define STAP_PROBE3(provider, name, arg1, arg2, arg3) \ + _SDT_PROBE(provider, name, 3, (arg1, arg2, arg3)) +#define STAP_PROBE4(provider, name, arg1, arg2, arg3, arg4) \ + _SDT_PROBE(provider, name, 4, (arg1, arg2, arg3, arg4)) +#define STAP_PROBE5(provider, name, arg1, arg2, arg3, arg4, arg5) \ + _SDT_PROBE(provider, name, 5, (arg1, arg2, arg3, arg4, arg5)) +#define STAP_PROBE6(provider, name, arg1, arg2, arg3, arg4, arg5, arg6) \ + _SDT_PROBE(provider, name, 6, (arg1, arg2, arg3, arg4, arg5, arg6)) +#define STAP_PROBE7(provider, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + _SDT_PROBE(provider, name, 7, (arg1, arg2, arg3, arg4, arg5, arg6, arg7)) +#define STAP_PROBE8(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) \ + _SDT_PROBE(provider, name, 8, (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) +#define STAP_PROBE9(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\ + _SDT_PROBE(provider, name, 9, (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)) +#define STAP_PROBE10(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) \ + _SDT_PROBE(provider, name, 10, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)) +#define STAP_PROBE11(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11) \ + _SDT_PROBE(provider, name, 11, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)) +#define STAP_PROBE12(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12) \ + _SDT_PROBE(provider, name, 12, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)) + +/* This STAP_PROBEV macro can be used in variadic scenarios, where the + number of probe arguments is not known until compile time. Since + variadic macro support may vary with compiler options, you must + pre-#define SDT_USE_VARIADIC to enable this type of probe. + + The trick to count __VA_ARGS__ was inspired by this post by + Laurent Deniau : + http://groups.google.com/group/comp.std.c/msg/346fc464319b1ee5 + + Note that our _SDT_NARG is called with an extra 0 arg that's not + counted, so we don't have to worry about the behavior of macros + called without any arguments. */ + +#define _SDT_NARG(...) __SDT_NARG(__VA_ARGS__, 12,11,10,9,8,7,6,5,4,3,2,1,0) +#define __SDT_NARG(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12, N, ...) N +#ifdef SDT_USE_VARIADIC +#define _SDT_PROBE_N(provider, name, N, ...) \ + _SDT_PROBE(provider, name, N, (__VA_ARGS__)) +#define STAP_PROBEV(provider, name, ...) \ + _SDT_PROBE_N(provider, name, _SDT_NARG(0, ##__VA_ARGS__), ##__VA_ARGS__) +#endif + +/* These macros are for use in asm statements. You must compile + with -std=gnu99 or -std=c99 to use the STAP_PROBE_ASM macro. + + The STAP_PROBE_ASM macro generates a quoted string to be used in the + template portion of the asm statement, concatenated with strings that + contain the actual assembly code around the probe site. + + For example: + + asm ("before\n" + STAP_PROBE_ASM(provider, fooprobe, %eax 4(%esi)) + "after"); + + emits the assembly code for "before\nafter", with a probe in between. + The probe arguments are the %eax register, and the value of the memory + word located 4 bytes past the address in the %esi register. Note that + because this is a simple asm, not a GNU C extended asm statement, these + % characters do not need to be doubled to generate literal %reg names. + + In a GNU C extended asm statement, the probe arguments can be specified + using the macro STAP_PROBE_ASM_TEMPLATE(n) for n arguments. The paired + macro STAP_PROBE_ASM_OPERANDS gives the C values of these probe arguments, + and appears in the input operand list of the asm statement. For example: + + asm ("someinsn %0,%1\n" // %0 is output operand, %1 is input operand + STAP_PROBE_ASM(provider, fooprobe, STAP_PROBE_ASM_TEMPLATE(3)) + "otherinsn %[namedarg]" + : "r" (outvar) + : "g" (some_value), [namedarg] "i" (1234), + STAP_PROBE_ASM_OPERANDS(3, some_value, some_ptr->field, 1234)); + + This is just like writing: + + STAP_PROBE3(provider, fooprobe, some_value, some_ptr->field, 1234)); + + but the probe site is right between "someinsn" and "otherinsn". + + The probe arguments in STAP_PROBE_ASM can be given as assembly + operands instead, even inside a GNU C extended asm statement. + Note that these can use operand templates like %0 or %[name], + and likewise they must write %%reg for a literal operand of %reg. */ + +#define _SDT_ASM_BODY_1(p,n,...) _SDT_ASM_BODY(p,n,_SDT_ASM_SUBSTR,(__VA_ARGS__)) +#define _SDT_ASM_BODY_2(p,n,...) _SDT_ASM_BODY(p,n,/*_SDT_ASM_STRING */,__VA_ARGS__) +#define _SDT_ASM_BODY_N2(p,n,no,...) _SDT_ASM_BODY_ ## no(p,n,__VA_ARGS__) +#define _SDT_ASM_BODY_N1(p,n,no,...) _SDT_ASM_BODY_N2(p,n,no,__VA_ARGS__) +#define _SDT_ASM_BODY_N(p,n,...) _SDT_ASM_BODY_N1(p,n,_SDT_NARG(0, __VA_ARGS__),__VA_ARGS__) + +#if __STDC_VERSION__ >= 199901L +# define STAP_PROBE_ASM(provider, name, ...) \ + _SDT_ASM_BODY_N(provider, name, __VA_ARGS__) \ + _SDT_ASM_BASE +# define STAP_PROBE_ASM_OPERANDS(n, ...) _SDT_ASM_OPERANDS_##n(__VA_ARGS__) +#else +# define STAP_PROBE_ASM(provider, name, args) \ + _SDT_ASM_BODY(provider, name, /* _SDT_ASM_STRING */, (args)) \ + _SDT_ASM_BASE +#endif +#define STAP_PROBE_ASM_TEMPLATE(n) _SDT_ASM_TEMPLATE_##n,"use _SDT_ASM_TEMPLATE_" + + +/* DTrace compatible macro names. */ +#define DTRACE_PROBE(provider,probe) \ + STAP_PROBE(provider,probe) +#define DTRACE_PROBE1(provider,probe,parm1) \ + STAP_PROBE1(provider,probe,parm1) +#define DTRACE_PROBE2(provider,probe,parm1,parm2) \ + STAP_PROBE2(provider,probe,parm1,parm2) +#define DTRACE_PROBE3(provider,probe,parm1,parm2,parm3) \ + STAP_PROBE3(provider,probe,parm1,parm2,parm3) +#define DTRACE_PROBE4(provider,probe,parm1,parm2,parm3,parm4) \ + STAP_PROBE4(provider,probe,parm1,parm2,parm3,parm4) +#define DTRACE_PROBE5(provider,probe,parm1,parm2,parm3,parm4,parm5) \ + STAP_PROBE5(provider,probe,parm1,parm2,parm3,parm4,parm5) +#define DTRACE_PROBE6(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6) \ + STAP_PROBE6(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6) +#define DTRACE_PROBE7(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7) \ + STAP_PROBE7(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7) +#define DTRACE_PROBE8(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) \ + STAP_PROBE8(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) +#define DTRACE_PROBE9(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) \ + STAP_PROBE9(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) +#define DTRACE_PROBE10(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) \ + STAP_PROBE10(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) +#define DTRACE_PROBE11(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11) \ + STAP_PROBE11(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11) +#define DTRACE_PROBE12(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11,parm12) \ + STAP_PROBE12(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11,parm12) + + +#endif /* sys/sdt.h */ diff --git a/test/unittest/usdt/tst.usdt-notes.r b/test/unittest/usdt/tst.usdt-notes.r new file mode 100644 index 00000000..db6d18cb --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes.r @@ -0,0 +1,14 @@ +test:main:zero +test:main:one:1 +test:main:two:2:3 +test:main:three:4:5:7 +test:main:four:7:8:9:10 +test:main:five:11:12:13:14:15 +test:main:six:16:17:18:19:20:21 +test:main:seven:22:23:24:25:26:27:28 +test:main:eight:29:30:31:32:33:34:35:36 +test:main:nine:37:38:39:40:41:42:43:44:45 +test:main:ten:46:47:48:49:50:51:52:53:54:55 +test:main:eleven:56:57:58:59:60:61:62:63:64:65 +test:main:twelve:67:68:69:70:71:72:73:74:75:76 + diff --git a/test/unittest/usdt/tst.usdt-notes.sh b/test/unittest/usdt/tst.usdt-notes.sh new file mode 100755 index 00000000..364ba8db --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes.sh @@ -0,0 +1,121 @@ +#!/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 covers all USDT probes fired by the DTRACE_PROBEn macros. +# Arguments values are checked only for first 10 arguments because +# there is support for arg0 ... arg9 only at this moment. + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="-I${PWD}/test/unittest/usdt" + +DIRNAME="$tmpdir/usdt-notes.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > test.c < + +int +main(int argc, char **argv) +{ + DTRACE_PROBE(test_prov, zero); + DTRACE_PROBE1(test_prov, one, argc); + DTRACE_PROBE2(test_prov, two, 2, 3); + DTRACE_PROBE3(test_prov, three, 4, 5, 7); + DTRACE_PROBE4(test_prov, four, 7, 8, 9, 10); + DTRACE_PROBE5(test_prov, five, 11, 12, 13, 14, 15); + DTRACE_PROBE6(test_prov, six, 16, 17, 18, 19, 20, 21); + DTRACE_PROBE7(test_prov, seven, 22, 23, 24, 25, 26, 27, 28); + DTRACE_PROBE8(test_prov, eight, 29, 30, 31, 32, 33, 34, 35, 36); + DTRACE_PROBE9(test_prov, nine, 37, 38, 39, 40, 41, 42, 43, 44, 45); + DTRACE_PROBE10(test_prov, ten, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55); + DTRACE_PROBE11(test_prov, eleven, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66); + DTRACE_PROBE12(test_prov, twelve, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78); +} +EOF + +${CC} ${CFLAGS} -o test test.c +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi + +$dtrace -c ./test -qs /dev/stdin < References: <20250129144401.505186-1-alan.maguire@oracle.com> Message-ID: <20250129144401.505186-4-alan.maguire@oracle.com> To ensure USDT notes are found/fire for shared libraries, create a shared library and trace the USDT probes in it. To ensure the library is loaded when DTrace has started, call it early in the program lifetime and sleep until DTrace starts; at that point trace the probes with the pid and ensure they fire with expected args. Signed-off-by: Alan Maguire --- test/unittest/usdt/tst.usdt-notes-lib.r | 14 +++ test/unittest/usdt/tst.usdt-notes-lib.sh | 145 +++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 test/unittest/usdt/tst.usdt-notes-lib.r create mode 100755 test/unittest/usdt/tst.usdt-notes-lib.sh diff --git a/test/unittest/usdt/tst.usdt-notes-lib.r b/test/unittest/usdt/tst.usdt-notes-lib.r new file mode 100644 index 00000000..cab7b6d5 --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes-lib.r @@ -0,0 +1,14 @@ +libusdttest.so:libfn:zero +libusdttest.so:libfn:one:1 +libusdttest.so:libfn:two:2:3 +libusdttest.so:libfn:three:4:5:7 +libusdttest.so:libfn:four:7:8:9:10 +libusdttest.so:libfn:five:11:12:13:14:15 +libusdttest.so:libfn:six:16:17:18:19:20:21 +libusdttest.so:libfn:seven:22:23:24:25:26:27:28 +libusdttest.so:libfn:eight:29:30:31:32:33:34:35:36 +libusdttest.so:libfn:nine:37:38:39:40:41:42:43:44:45 +libusdttest.so:libfn:ten:46:47:48:49:50:51:52:53:54:55 +libusdttest.so:libfn:eleven:56:57:58:59:60:61:62:63:64:65 +libusdttest.so:libfn:twelve:67:68:69:70:71:72:73:74:75:76 + diff --git a/test/unittest/usdt/tst.usdt-notes-lib.sh b/test/unittest/usdt/tst.usdt-notes-lib.sh new file mode 100755 index 00000000..ed87e9f5 --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes-lib.sh @@ -0,0 +1,145 @@ +#!/bin/bash +# +# Oracle Linux DTrace. +# Copyright (c) 2025, 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 covers all USDT probes fired by the DTRACE_PROBEn macros. +# Arguments values are checked only for first 10 arguments because +# there is support for arg0 ... arg9 only at this moment. + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="-I${PWD}/test/unittest/usdt" + +DIRNAME="$tmpdir/usdt-notes.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > libusdttest.c < + +void +libfn(int argc, char **argv) +{ + if (argc == 0 && argv == 0) + return; + DTRACE_PROBE(test_prov, zero); + DTRACE_PROBE1(test_prov, one, argc); + DTRACE_PROBE2(test_prov, two, 2, 3); + DTRACE_PROBE3(test_prov, three, 4, 5, 7); + DTRACE_PROBE4(test_prov, four, 7, 8, 9, 10); + DTRACE_PROBE5(test_prov, five, 11, 12, 13, 14, 15); + DTRACE_PROBE6(test_prov, six, 16, 17, 18, 19, 20, 21); + DTRACE_PROBE7(test_prov, seven, 22, 23, 24, 25, 26, 27, 28); + DTRACE_PROBE8(test_prov, eight, 29, 30, 31, 32, 33, 34, 35, 36); + DTRACE_PROBE9(test_prov, nine, 37, 38, 39, 40, 41, 42, 43, 44, 45); + DTRACE_PROBE10(test_prov, ten, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55); + DTRACE_PROBE11(test_prov, eleven, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66); + DTRACE_PROBE12(test_prov, twelve, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78); +} +EOF + +cat > test.c < + +extern void libfn(int argc, char **argv); + +int +main(int argc, char **argv) +{ + libfn(0, 0); + sleep(10); + libfn(argc, argv); + return 0; +} +EOF + +${CC} ${CFLAGS} -c -fpic libusdttest.c +${CC} -shared -o libusdttest.so libusdttest.o +${CC} -L. ${CFLAGS} -o test test.c -lusdttest +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi + +export LD_LIBRARY_PATH=.:${LD_LIBRARY_PATH} +LD_LIBRARY_PATH=.:${LD_LIBRARY_PATH} ./test & +PID=$! +sleep 5 +$dtrace -p $PID -qs /dev/stdin < References: <20250129144401.505186-1-alan.maguire@oracle.com> Message-ID: <20250129144401.505186-5-alan.maguire@oracle.com> Add a test exercising various arg types supported by USDT notes; register values, register + offset and constants. The test generates a binary with probes represented as follows on x86_64: Displaying notes found in: .note.stapsdt Owner Data size Description stapsdt 0x00000048 NT_STAPSDT (SystemTap probe descriptors) Provider: test_prov Name: args Location: 0x0000000000400557, Base: 0x00000000004005f8, Semaphore: 0x0000000000000000 Arguments: -4 at -4(%rbp) 8@%rax 8@%rdx -4@$18 Verify we get expected data for the probe arguments. Signed-off-by: Alan Maguire --- libdtrace/dt_pid.c | 61 ++++++++++++++--------- test/unittest/usdt/tst.usdt-notes-args.r | 2 + test/unittest/usdt/tst.usdt-notes-args.sh | 51 +++++++++++++++++++ 3 files changed, 91 insertions(+), 23 deletions(-) create mode 100644 test/unittest/usdt/tst.usdt-notes-args.r create mode 100755 test/unittest/usdt/tst.usdt-notes-args.sh diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index 5608e380..cac52616 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -960,7 +960,7 @@ static int dt_usdt_note_parse_arg(char **argstr, struct dt_usdt_arg *a) static int dt_usdt_notes_parse(dtrace_hdl_t *dtp, dt_proc_t *dpr, dtrace_probedesc_t *pdp, dt_pcb_t *pcb, - const dt_provider_t *pvp, const char *path, + const dt_provider_t *pvp, char *path, unsigned long base_addr) { Elf *elf; @@ -969,8 +969,10 @@ static int dt_usdt_notes_parse(dtrace_hdl_t *dtp, dt_proc_t *dpr, GElf_Nhdr nhdr; size_t shstrndx, noff, doff, off, n; Elf_Data *data; + GElf_Ehdr ehdr; int i, ret = 0; int fd = -1; + char *mod; dt_dprintf("Scanning for USDT probes in ELF notes in '%s' (pid %i) matching %s:%s:%s\n", path, dpr->dpr_pid, pdp->mod, pdp->fun, pdp->prb); @@ -982,17 +984,38 @@ static int dt_usdt_notes_parse(dtrace_hdl_t *dtp, dt_proc_t *dpr, path, strerror(errno)); return -1; } + mod = strrchr(path, '/'); + if (mod) + mod++; + else + mod = path; elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); // ELF_C_READ ? assert(elf_kind(elf) == ELF_K_ELF); elf_getshdrstrndx(elf, &shstrndx); + if (gelf_getehdr(elf, &ehdr)) { + switch (ehdr.e_type) { + case ET_EXEC: + /* binary does not require base addr adjustment */ + base_addr = 0; + break; + case ET_DYN: + break; + default: + dt_dprintf("unexpected ELF hdr type 0x%x for '%s'\n", + ehdr.e_type, path); + ret = -1; + goto out; + } + } + while (1) { char *secname; scn = elf_nextscn(elf, scn); if (scn == NULL) { /* no ELF notes found, not an error */ - return 0; + goto out; } assert(gelf_getshdr(scn, &shdr) != NULL); @@ -1010,7 +1033,6 @@ static int dt_usdt_notes_parse(dtrace_hdl_t *dtp, dt_proc_t *dpr, pid_probespec_t psp = {0}; char *prv, *prb; const char *fun; - char mod[PATH_MAX]; char *dbuf = (char *)data->d_buf; long *addrs = data->d_buf + doff; /* 3 addrs are loc/base/semaphore */ GElf_Sym sym; @@ -1057,12 +1079,7 @@ static int dt_usdt_notes_parse(dtrace_hdl_t *dtp, dt_proc_t *dpr, prv, prb, path, addrs[0], addrs[1], nargs); psp.pps_type = DTPPT_USDT; psp.pps_prv = prv; - if (dt_Pobjname(dtp, dpr->dpr_pid, base_addr + addrs[0], mod, - sizeof(mod)) == NULL) { - dt_dprintf("cannot determine mod name for 0x%lx\n", addrs[0]); - mod[0] = '\0'; - } - psp.pps_mod = basename(mod); + psp.pps_mod = mod; psp.pps_prb = prb; if (elf_getphdrnum(elf, &n)) continue; @@ -1124,6 +1141,7 @@ static int dt_usdt_notes_parse(dtrace_hdl_t *dtp, dt_proc_t *dpr, break; } out: + elf_end(elf); close(fd); return ret; } @@ -1557,9 +1575,10 @@ dt_pid_create_usdt_notes_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, const dt_provider_t *pvp; char path[PATH_MAX + 1]; dt_proc_t *dpr = NULL; + char line[1024]; FILE *fp = NULL; pid_t pid = 0; - int err; + int err = 0; /* only specific pids are support for ELF notes for now... */ while (isdigit(*(pidstr - 1))) @@ -1580,13 +1599,8 @@ dt_pid_create_usdt_notes_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, } dpr = dt_proc_lookup(dtp, pid); assert(dpr != NULL); - snprintf(path, sizeof(path), "/proc/%d/exe", dpr->dpr_pid); - err = dt_usdt_notes_parse(dtp, dpr, pdp, pcb, pvp, path, 0); - if (err) - goto out; snprintf(path, sizeof(path), "/proc/%d/maps", pid); - fp = fopen(path, "r"); if (!fp) { dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, @@ -1594,20 +1608,21 @@ dt_pid_create_usdt_notes_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, err = 1; goto out; } - do { + while (fgets(line, sizeof(line) - 1, fp) != NULL) { long addr_start, addr_end, file_offset; long dev_major, dev_minor; unsigned long inode; char name[PATH_MAX + 1]; char perm[5]; + int ret; - - if (fscanf(fp, - "%lx-%lx %4s %lx %lx:%lx %lu %[^\n]", - &addr_start, &addr_end, perm, &file_offset, - &dev_major, &dev_minor, &inode, name) != 8 || - !strchr(perm, 'x') || strchr(name, '[') != NULL) + ret = sscanf(line, + "%lx-%lx %4s %lx %lx:%lx %lu %[^\n]", + &addr_start, &addr_end, perm, &file_offset, + &dev_major, &dev_minor, &inode, name); + if (ret != 8 || !strchr(perm, 'x') || strchr(name, '[') != NULL) continue; + /* libstapsdt uses an memfd-based library to dynamically create * stapsdt notes for dynamic languages like python; we need * the associated /proc//fds/ fd to read these notes. @@ -1642,7 +1657,7 @@ dt_pid_create_usdt_notes_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, goto out; } } - } while (!feof(fp)); + } out: if (fp) fclose(fp); diff --git a/test/unittest/usdt/tst.usdt-notes-args.r b/test/unittest/usdt/tst.usdt-notes-args.r new file mode 100644 index 00000000..42bca19f --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes-args.r @@ -0,0 +1,2 @@ +test:main:args:2:./test:val:18 + diff --git a/test/unittest/usdt/tst.usdt-notes-args.sh b/test/unittest/usdt/tst.usdt-notes-args.sh new file mode 100755 index 00000000..7c8ea37b --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes-args.sh @@ -0,0 +1,51 @@ +#!/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 covers all USDT probes fired by the DTRACE_PROBEn macros. +# Arguments values are checked only for first 10 arguments because +# there is support for arg0 ... arg9 only at this moment. + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="-I${PWD}/test/unittest/usdt" + +DIRNAME="$tmpdir/usdt-notes.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > test.c < + +int +main(int argc, char **argv) +{ + DTRACE_PROBE4(test_prov, args, argc, argv[0], argv[1] + 4, 18); +} +EOF + +${CC} ${CFLAGS} -o test test.c +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi + +$dtrace -c './test arg1val' -qs /dev/stdin < This series adds support (patch 1) for ELF-note defined USDT probes in binaries and libraries; patches 2-4 add tests. Basic pid-specific USDT support is added; i.e. it is necessary to specify the target pid in the provider name such as "example1234" ; future work could add pid wildcarding. ELF note defined probes are defined by including sys/sdt.h from the systemtap-sdt-devel package, and are defined in C programs via DTRACE_PROBEn(provider, probe, [args...]) See the tests for concrete examples. For python, go, etc, USDT probes can be added via libstapsdt [1] and associated language-specific bindings. This allows users of those languages to add USDT probes too. For example, the following example program adds a "pythonapp" probe "firstProbe" using the python-specific libstapsdt binding: #!/usr/bin/python3 from time import sleep import stapsdt provider = stapsdt.Provider("pythonapp") probe = provider.add_probe( "firstProbe", stapsdt.ArgTypes.uint64, stapsdt.ArgTypes.int32) provider.load() while True: print("Firing probe...") if probe.fire("My little probe", 42): print("Probe fired!") sleep(1) We can then trace this via dtrace: # dtrace -n 'pythonapp503211:::* { printf("args %s, %d\n", copyinstr(arg0), arg1); }' dtrace: description 'pythonapp503211:::* ' matched 1 probe CPU ID FUNCTION:NAME 6 286628 :firstProbe args My little probe, 42 [1] https://github.com/linux-usdt/libstapsdt Alan Maguire (4): USDT: support ELF-note-defined probes selftests/usdt: add test for USDT note-defined probe firing, args selftests/usdt: add test for USDT notes in shared library selftests/usdt: add test covering different forms of USDT note args include/dtrace/pid.h | 29 ++ libdtrace/dt_cg.c | 47 ++ libdtrace/dt_cg.h | 1 + libdtrace/dt_pid.c | 466 ++++++++++++++++++++ libdtrace/dt_prov_uprobe.c | 19 +- test/unittest/usdt/sdt_notes.h | 504 ++++++++++++++++++++++ test/unittest/usdt/tst.usdt-notes-args.r | 2 + test/unittest/usdt/tst.usdt-notes-args.sh | 51 +++ test/unittest/usdt/tst.usdt-notes-lib.r | 14 + test/unittest/usdt/tst.usdt-notes-lib.sh | 145 +++++++ test/unittest/usdt/tst.usdt-notes.r | 14 + test/unittest/usdt/tst.usdt-notes.sh | 121 ++++++ 12 files changed, 1406 insertions(+), 7 deletions(-) create mode 100644 test/unittest/usdt/sdt_notes.h create mode 100644 test/unittest/usdt/tst.usdt-notes-args.r create mode 100755 test/unittest/usdt/tst.usdt-notes-args.sh create mode 100644 test/unittest/usdt/tst.usdt-notes-lib.r create mode 100755 test/unittest/usdt/tst.usdt-notes-lib.sh create mode 100644 test/unittest/usdt/tst.usdt-notes.r create mode 100755 test/unittest/usdt/tst.usdt-notes.sh -- 2.43.5 From alan.maguire at oracle.com Wed Jan 29 14:55:19 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Wed, 29 Jan 2025 14:55:19 +0000 Subject: [DTrace-devel] [PATCH v2 1/4] USDT: support ELF-note-defined probes In-Reply-To: <20250129145522.512341-1-alan.maguire@oracle.com> References: <20250129145522.512341-1-alan.maguire@oracle.com> Message-ID: <20250129145522.512341-2-alan.maguire@oracle.com> As well as using dtrace -G to generate USDT probes, they can be added via ELF notes describing the probe. Read ELF notes from /proc//exe and associated libraries, and parse them to retrieve uprobe address and argument-related info to create the associated uprobe. The painful part here is retrieving info from the string of USDT arguments in the ELF note such that we can generate trampoline code to retrieve the probe arguments. Probe arguments can be either constants, register values or dereferences from register values (plus offset). Use bpf_probe_read[_user] for the latter case. Translating from the register names in the USDT argument string is platform-specific, so we use arrays mapping the register names used to the appropriate pt_regs field name, along with an offset (for the aarch64 case where the regs[] array in user_pt_regs is used). Wildcarded pid USDT probes are not yet supported; a specific pid is required. As well as supporting ELF-note defined probes in programs and libraries, this patch supports dynamically-created probes that are created via libstapsdt [1]. libstapsdt allows dynamic languages like python to declare and fire probes by dynamically creating a memfd-based shared library containing ELF notes for the probes. With these changes we can also trace these probes. This is very useful since libstapsdt has python, NodeJS, go and luaJIT bindings. [1] https://github.com/linux-usdt/libstapsdt Signed-off-by: Alan Maguire --- include/dtrace/pid.h | 29 +++ libdtrace/dt_cg.c | 47 ++++ libdtrace/dt_cg.h | 1 + libdtrace/dt_pid.c | 466 +++++++++++++++++++++++++++++++++++++ libdtrace/dt_prov_uprobe.c | 19 +- 5 files changed, 555 insertions(+), 7 deletions(-) diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h index c53e6004..a8e26da4 100644 --- a/include/dtrace/pid.h +++ b/include/dtrace/pid.h @@ -26,6 +26,27 @@ typedef enum pid_probetype { DTPPT_IS_ENABLED } pid_probetype_t; +#define DT_USDT_MAX_ARGS 10 + +enum dt_usdt_arg_type { + DT_USDT_ARG_NONE = 0, + DT_USDT_ARG_CONST, + DT_USDT_ARG_REG, + DT_USDT_ARG_REG_DEREF +}; + +struct dt_usdt_arg { + enum dt_usdt_arg_type ua_type; + int ua_val_sz; + int ua_val_off; + int64_t ua_const_val; + const char *ua_regs_name; /* pt_regs/user_pt_regs */ + const char *ua_regs_field; /* x0/rsp etc */ + int ua_regs_field_off; /* used for array regs[] */ +}; + +typedef struct dt_usdt_arg dt_usdt_arg_t; + typedef struct pid_probespec { pid_probetype_t pps_type; /* probe type */ char *pps_prv; /* provider (without pid) */ @@ -44,6 +65,14 @@ typedef struct pid_probespec { size_t pps_xargvlen; /* (high estimate of) length of array */ int8_t *pps_argmap; /* mapped arg indexes */ + int pps_nuargs; /* number of arg specs in + * pps_uargs + */ + dt_usdt_arg_t pps_uargs[DT_USDT_MAX_ARGS]; + /* USDT ELF note-defined + * provider arguments. + */ + /* * Fields below this point do not apply to underlying probes. */ diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index e7e3a132..2c8f8210 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -651,6 +651,53 @@ dt_cg_tramp_copy_rval_from_regs(dt_pcb_t *pcb) emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), 0)); } +void +dt_cg_tramp_copy_args_from_usdt_spec(dt_pcb_t *pcb, const dt_usdt_arg_t *args) +{ + dtrace_hdl_t *dtp = pcb->pcb_hdl; + dt_irlist_t *dlp = &pcb->pcb_ir; + int reg_val_off, i; + + for (i = 0; i < DT_USDT_MAX_ARGS; i++) { + const dt_usdt_arg_t *arg = &args[i]; + uint_t lbl_ok = dt_irlist_label(dlp); + + switch (arg->ua_type) { + case DT_USDT_ARG_NONE: + return; + case DT_USDT_ARG_CONST: + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), + arg->ua_const_val)); + break; + case DT_USDT_ARG_REG: + case DT_USDT_ARG_REG_DEREF: + reg_val_off = dt_cg_ctf_offsetof(arg->ua_regs_name, + arg->ua_regs_field, NULL, 0); + reg_val_off += arg->ua_regs_field_off; + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, + reg_val_off)); + /* do direct register value copy */ + if (arg->ua_type == DT_USDT_ARG_REG) { + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), + BPF_REG_0)); + break; + } + /* otherwise call bpf_probe_read[_user] to get dereferenced value. + */ + emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_7)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DMST_ARG(i))); + emit(dlp, BPF_MOV_IMM(BPF_REG_2, abs(arg->ua_val_sz))); + emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, arg->ua_val_off)); + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user])); + emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_ok)); + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), 0)); + emitl(dlp, lbl_ok, BPF_NOP()); + break; + } + } +} + static dt_node_t * dt_cg_tramp_var(const char *name) { diff --git a/libdtrace/dt_cg.h b/libdtrace/dt_cg.h index fb26c125..24257f0b 100644 --- a/libdtrace/dt_cg.h +++ b/libdtrace/dt_cg.h @@ -28,6 +28,7 @@ extern void dt_cg_tramp_copy_regs(dt_pcb_t *pcb); extern void dt_cg_tramp_copy_args_from_regs(dt_pcb_t *pcb, int called); extern void dt_cg_tramp_copy_pc_from_regs(dt_pcb_t *pcb); extern void dt_cg_tramp_copy_rval_from_regs(dt_pcb_t *pcb); +extern void dt_cg_tramp_copy_args_from_usdt_spec(dt_pcb_t *pcb, const dt_usdt_arg_t *args); extern void dt_cg_tramp_decl_var(dt_pcb_t *pcb, dt_ident_t *idp); extern void dt_cg_tramp_get_var(dt_pcb_t *pcb, const char *name, int isstore, int reg); diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index 4d53c023..cac52616 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -28,6 +28,8 @@ #if defined(__amd64) #include #endif +#include +#include #include #include @@ -780,6 +782,369 @@ validate_dof_record(const char *path, const dof_parsed_t *parsed, return 1; } +#define SEC_USDT_NOTE ".note.stapsdt" +#define NAME_USDT_NOTE "stapsdt" + +struct pt_regs_info { + const char ua_name[8]; + const char name[8]; + int off; +} pt_regs_info[] = { + +#if defined(__aarch64__) + { "sp", "sp", 0 }, + { "x0", "regs", 0 }, + { "x1", "regs", 1 * sizeof(unsigned long) }, + { "x2", "regs", 2 * sizeof(unsigned long) }, + { "x3", "regs", 3 * sizeof(unsigned long) }, + { "x4", "regs", 4 * sizeof(unsigned long) }, + { "x5", "regs", 5 * sizeof(unsigned long) }, + { "x6", "regs", 6 * sizeof(unsigned long) }, + { "x7", "regs", 7 * sizeof(unsigned long) }, + { "x8", "regs", 8 * sizeof(unsigned long) }, + { "x9", "regs", 9 * sizeof(unsigned long) }, + { "x10", "regs", 10 * sizeof(unsigned long) }, + { "x11", "regs", 11 * sizeof(unsigned long) }, + { "x12", "regs", 12 * sizeof(unsigned long) }, + { "x13", "regs", 13 * sizeof(unsigned long) }, + { "x14", "regs", 14 * sizeof(unsigned long) }, + { "x15", "regs", 15 * sizeof(unsigned long) }, + { "x16", "regs", 16 * sizeof(unsigned long) }, + { "x17", "regs", 17 * sizeof(unsigned long) }, + { "x18", "regs", 18 * sizeof(unsigned long) }, + { "x19", "regs", 19 * sizeof(unsigned long) }, + { "x20", "regs", 20 * sizeof(unsigned long) }, + { "x21", "regs", 21 * sizeof(unsigned long) }, + { "x222", "regs", 22 * sizeof(unsigned long) }, + { "x23", "regs", 23 * sizeof(unsigned long) }, + { "x24", "regs", 24 * sizeof(unsigned long) }, + { "x25", "regs", 25 * sizeof(unsigned long) }, + { "x26", "regs", 26 * sizeof(unsigned long) }, + { "x27", "regs", 27 * sizeof(unsigned long) }, + { "x28", "regs", 28 * sizeof(unsigned long) }, + { "x29", "regs", 29 * sizeof(unsigned long) }, + { "x30", "regs", 30 * sizeof(unsigned long) }, + { "x31", "regs", 31 * sizeof(unsigned long) } +#else + { "rip", "ip", 0 }, + { "eip", "ip", 0 }, + { "rax", "ax", 0 }, + { "eax", "ax", 0 }, + { "ax", "ax", 0 }, + { "al", "ax", 0 }, + { "rbx", "bx", 0 }, + { "ebx", "bx", 0 }, + { "bx", "bx", 0 }, + { "bl", "bx", 0 }, + { "rcx", "cx", 0 }, + { "ecx", "cx", 0 }, + { "cx", "cx", 0 }, + { "cl", "cx", 0 }, + { "rdx", "dx", 0 }, + { "edx", "dx", 0 }, + { "dx", "dx", 0 }, + { "dl", "dx", 0 }, + { "rsi", "si", 0 }, + { "esi", "si", 0 }, + { "si", "si", 0 }, + { "sil", "si", 0 }, + { "rdi", "di", 0 }, + { "edi", "di", 0 }, + { "di", "di", 0 }, + { "dil", "di", 0 }, + { "rbp", "bp", 0 }, + { "ebp", "bp", 0 }, + { "bp", "bp", 0 }, + { "bpl", "bp", 0 }, + { "rsp", "sp", 0 }, + { "esp", "sp", 0 }, + { "sp", "sp", 0 }, + { "spl", "sp", 0 } +#endif +}; + +static void dt_usdt_note_print_arg(dt_usdt_arg_t *a) +{ + switch (a->ua_type) { + case DT_USDT_ARG_NONE: + return; + case DT_USDT_ARG_CONST: + dt_dprintf("CONST %ld\n", a->ua_const_val); + break; + case DT_USDT_ARG_REG_DEREF: + dt_dprintf("REG DEREF (%s.%s + %d) + %d\n", + a->ua_regs_name, a->ua_regs_field, + a->ua_regs_field_off, a->ua_val_off); + break; + case DT_USDT_ARG_REG: + dt_dprintf("REG VALUE (%s.%s + %d)\n", + a->ua_regs_name, a->ua_regs_field, + a->ua_regs_field_off); + break; + } +} + +/* retrieve arguments; space-separated string of arguments of form: + * [-]numbytes@[optional_offset_from(]%regname[)] + * + * for example: + * + * -4 at -4(%rbp) means memory dereference of 4 bytes, 4 bytes + * offset from %rbp value. + * 8@(%rax) means memory dereference of 8 bytes from + * rax register value (no offset) + * 8@%rax means 8 bytes from rax register value (no deref). + * 4@$32 means 4 byte constant value 32 + */ +static int dt_usdt_note_parse_arg(char **argstr, struct dt_usdt_arg *a) +{ + char *arg = *argstr; + char reg[8] = {}; + int len; + + if (sscanf(arg, +#if defined(__aarch64__) + " %d @ \[ %[a-z0-9] , %d ] %n", + &a->ua_val_sz, reg, &a->ua_val_off, &len) +#else + " %d @ %d ( %%%8[^)] ) %n", + &a->ua_val_sz, &a->ua_val_off, reg, &len) +#endif + == 3) { + a->ua_type = DT_USDT_ARG_REG_DEREF; + } else if (sscanf(arg, +#if defined(__aarch64__) + " %d @ \[ %7[a-z0-9] ] %n", &a->ua_val_sz, reg, &len) +#else + " %d @ ( %%%7[^)] ) %n", &a->ua_val_sz, reg, &len) +#endif + == 2) { + a->ua_type = DT_USDT_ARG_REG_DEREF; + } else if (sscanf(arg, +#if defined(__x86_64__) + " %d @ $%ld %n", &a->ua_val_sz, &a->ua_const_val, &len) +#else + " %d @ %ld %n", &a->ua_val_sz, &a->ua_const_val, &len) +#endif + == 2) { + a->ua_type = DT_USDT_ARG_CONST; + } else if (sscanf(arg, +#if defined(__aarch64__) + " %d @ %7[a-z0-9] %n", &a->ua_val_sz, reg, &len) +#else + " %d @ %%%7s %n", &a->ua_val_sz, reg, &len) +#endif + == 2) { + a->ua_type = DT_USDT_ARG_REG; + } else { + return -1; + } + if (strlen(reg) > 0) { + int i; + +#if defined(__aarch64__) + a->ua_regs_name = "struct user_pt_regs"; +#else + a->ua_regs_name = "struct pt_regs"; +#endif + for (i = 0; i < ARRAY_SIZE(pt_regs_info); i++) { + if (strcmp(pt_regs_info[i].ua_name, reg)) + continue; + a->ua_regs_field = pt_regs_info[i].name; + a->ua_regs_field_off = pt_regs_info[i].off; + } + } + *argstr += len; + return 0; +} + +static int dt_usdt_notes_parse(dtrace_hdl_t *dtp, dt_proc_t *dpr, + dtrace_probedesc_t *pdp, dt_pcb_t *pcb, + const dt_provider_t *pvp, char *path, + unsigned long base_addr) +{ + Elf *elf; + Elf_Scn *scn = NULL; + GElf_Shdr shdr; + GElf_Nhdr nhdr; + size_t shstrndx, noff, doff, off, n; + Elf_Data *data; + GElf_Ehdr ehdr; + int i, ret = 0; + int fd = -1; + char *mod; + + dt_dprintf("Scanning for USDT probes in ELF notes in '%s' (pid %i) matching %s:%s:%s\n", + path, dpr->dpr_pid, pdp->mod, pdp->fun, pdp->prb); + + fd = open(path, O_RDONLY); + if (fd < 0) { + dt_pid_error(dtp, pcb, dpr, D_PROC_USDT, + "Cannot open %s: %s\n", + path, strerror(errno)); + return -1; + } + mod = strrchr(path, '/'); + if (mod) + mod++; + else + mod = path; + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); // ELF_C_READ ? + assert(elf_kind(elf) == ELF_K_ELF); + elf_getshdrstrndx(elf, &shstrndx); + + if (gelf_getehdr(elf, &ehdr)) { + switch (ehdr.e_type) { + case ET_EXEC: + /* binary does not require base addr adjustment */ + base_addr = 0; + break; + case ET_DYN: + break; + default: + dt_dprintf("unexpected ELF hdr type 0x%x for '%s'\n", + ehdr.e_type, path); + ret = -1; + goto out; + } + } + + while (1) { + char *secname; + + scn = elf_nextscn(elf, scn); + if (scn == NULL) { + /* no ELF notes found, not an error */ + goto out; + } + assert(gelf_getshdr(scn, &shdr) != NULL); + + secname = elf_strptr(elf, shstrndx, shdr.sh_name); + if (strcmp(secname, SEC_USDT_NOTE) == 0 && + shdr.sh_type == SHT_NOTE) + break; + } + /* No ELF notes, just bail. */ + if (scn == NULL) + goto out; + data = elf_getdata(scn, 0); + for (off = 0; + (off = gelf_getnote(data, off, &nhdr, &noff, &doff)) > 0;) { + pid_probespec_t psp = {0}; + char *prv, *prb; + const char *fun; + char *dbuf = (char *)data->d_buf; + long *addrs = data->d_buf + doff; /* 3 addrs are loc/base/semaphore */ + GElf_Sym sym; + const prmap_t *pmp; + int nargs = 0; + + if (strncmp(dbuf + noff, NAME_USDT_NOTE, nhdr.n_namesz) != 0) + continue; + prv = dbuf + doff + (3*sizeof(long)); + /* ensure prv/prb is null-terminated */ + assert(strlen(prv) < nhdr.n_descsz); + prb = prv + strlen(prv) + 1; + assert(strlen(prb) < nhdr.n_descsz); + if (strncmp(pdp->prv, prv, strlen(prv)) != 0) + continue; + if (strcmp(pdp->prb, "*") != 0 && strcmp(pdp->prb, prb) != 0) + continue; + /* retrieve arguments; space-separated string of arguments + * in form: + * [-]numbytes@[optional_offset_from(]%regname[)] + * + * for example: + * + * -4 at -4(%rbp) means memory dereference of 4 bytes, 4 bytes + * offset from %rbp value. + * 8@(%rax) means memory dereference of 8 bytes from + * rax register value (no offset) + * 8@%rax means 8 bytes from rax register value (no deref). + * 4@$32 means 4 byte constant value 32 + */ + if (prb + strlen(prb) + 1 < dbuf + doff + nhdr.n_descsz) { + char *argstr = prb + strlen(prb) + 1; + + while (dt_usdt_note_parse_arg(&argstr, + &psp.pps_uargs[nargs]) == 0 && + nargs < DT_USDT_MAX_ARGS) { + dt_usdt_note_print_arg(&psp.pps_uargs[nargs]); + nargs++; + } + psp.pps_nuargs = nargs; + + } + dt_dprintf("found ELF note for provider '%s', probe '%s' in %s, loc 0x%lx, base 0x%lx, nargs %d\n", + prv, prb, path, addrs[0], addrs[1], nargs); + psp.pps_type = DTPPT_USDT; + psp.pps_prv = prv; + psp.pps_mod = mod; + psp.pps_prb = prb; + if (elf_getphdrnum(elf, &n)) + continue; + for (i = 0; i < n; i++) { + GElf_Phdr phdr; + + if (!gelf_getphdr(elf, i, &phdr)) + break; + + if (addrs[0] < phdr.p_vaddr || + addrs[0] > phdr.p_vaddr + phdr.p_memsz) + continue; + if (base_addr) + psp.pps_off = addrs[0]; + else + psp.pps_off = addrs[0] - phdr.p_vaddr + phdr.p_offset; + break; + } + if (!psp.pps_off) + continue; + psp.pps_nameoff = 0; + + pmp = Paddr_to_map(dpr->dpr_proc, base_addr + addrs[0]); + if (!pmp) { + dt_dprintf("%i: cannot determine 0x%lx's mapping\n", + Pgetpid(dpr->dpr_proc), psp.pps_off); + continue; + } + psp.pps_fn = Pmap_mapfile_name(dpr->dpr_proc, pmp); + if (psp.pps_fn == NULL) { + dt_pid_error(dtp, pcb, dpr, D_PROC_USDT, + "Cannot get name of mapping containing probe %s for pid %d\n", + psp.pps_prb, dpr->dpr_pid); + ret = -1; + break; + } + if (dt_Plookup_by_addr(dtp, dpr->dpr_pid, base_addr + addrs[0], + &fun, &sym) == 0) + psp.pps_fun = (char *)fun; + else + psp.pps_fun = ""; + psp.pps_dev = pmp->pr_dev; + psp.pps_inum = pmp->pr_inum; + psp.pps_pid = dpr->dpr_pid; + psp.pps_nameoff = 0; + + dt_dprintf("providing %s:%s:%s:%s for pid %d at addr 0x%lx\n", psp.pps_prv, + psp.pps_mod, psp.pps_fun, psp.pps_prb, psp.pps_pid, + base_addr + addrs[0]); + if (pvp->impl->provide_probe(dtp, &psp) < 0) { + dt_pid_error(dtp, pcb, dpr, D_PROC_USDT, + "failed to instantiate probe %s for pid %d: %s", + psp.pps_prb, psp.pps_pid, + dtrace_errmsg(dtp, dtrace_errno(dtp))); + ret = -1; + } + free(psp.pps_fn); + if (ret == -1) + break; + } +out: + elf_end(elf); + close(fd); + return ret; +} /* * Create underlying probes relating to the probespec passed on input. @@ -1202,6 +1567,105 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *p return err; } +static int +dt_pid_create_usdt_notes_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, + dt_pcb_t *pcb) +{ + const char *pidstr = &pdp->prv[strlen(pdp->prv)]; + const dt_provider_t *pvp; + char path[PATH_MAX + 1]; + dt_proc_t *dpr = NULL; + char line[1024]; + FILE *fp = NULL; + pid_t pid = 0; + int err = 0; + + /* only specific pids are support for ELF notes for now... */ + while (isdigit(*(pidstr - 1))) + pidstr--; + if (strlen(pidstr) > 0) + pid = atoll(pidstr); + if (!Pexists(pid)) + return 0; + pvp = dt_provider_lookup(dtp, "usdt"); + assert(pvp != NULL); + + if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING | + DTRACE_PROC_SHORTLIVED) < 0) { + dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, + "failed to grab process %d", + (int)pid); + return 1; + } + dpr = dt_proc_lookup(dtp, pid); + assert(dpr != NULL); + + snprintf(path, sizeof(path), "/proc/%d/maps", pid); + fp = fopen(path, "r"); + if (!fp) { + dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, + "no /proc/%d/maps found", (int)pid); + err = 1; + goto out; + } + while (fgets(line, sizeof(line) - 1, fp) != NULL) { + long addr_start, addr_end, file_offset; + long dev_major, dev_minor; + unsigned long inode; + char name[PATH_MAX + 1]; + char perm[5]; + int ret; + + ret = sscanf(line, + "%lx-%lx %4s %lx %lx:%lx %lu %[^\n]", + &addr_start, &addr_end, perm, &file_offset, + &dev_major, &dev_minor, &inode, name); + if (ret != 8 || !strchr(perm, 'x') || strchr(name, '[') != NULL) + continue; + + /* libstapsdt uses an memfd-based library to dynamically create + * stapsdt notes for dynamic languages like python; we need + * the associated /proc//fds/ fd to read these notes. + */ + if (strncmp(name, "/memfd:", strlen("/memfd:")) == 0) { + DIR *d; + struct dirent *dirent; + char *deleted; + + deleted = strstr(name, " (deleted)"); + *deleted = '\0'; + snprintf(path, sizeof(path), "/proc/%d/fd", pid); + d = opendir(path); + if (d == NULL) + continue; + while ((dirent = readdir(d)) != NULL) { + struct stat s; + + snprintf(path, sizeof(path), "/proc/%d/fd/%s", + pid, dirent->d_name); + if (stat(path, &s) != 0 || s.st_ino != inode) + continue; + if (dt_usdt_notes_parse(dtp, dpr, pdp, pcb, pvp, + path, addr_start) != 0) { + err = 1; + goto out; + } + } + } else { + if (dt_usdt_notes_parse(dtp, dpr, pdp, pcb, pvp, name, addr_start) != 0) { + err = 1; + goto out; + } + } + } +out: + if (fp) + fclose(fp); + dt_pid_fix_mod(NULL, pdp, dtp, dpr->dpr_pid); + dt_proc_release_unlock(dtp, pid); + return err; +} + int dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb) { @@ -1273,6 +1737,8 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t * free(globpat); globfree(&globbuf); + err = dt_pid_create_usdt_notes_probes(pdp, dtp, pcb); + /* If no errors, report success. */ if (err == 0) return 0; diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index 78d9aed6..08b60b44 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -51,6 +51,7 @@ static const char prvname[] = "uprobe"; #define PP_IS_ENABLED 0x4 #define PP_IS_USDT 0x8 #define PP_IS_MAPPED 0x10 +#define PP_IS_USDT_NOTE 0x20 typedef struct dt_uprobe { dev_t dev; @@ -58,6 +59,7 @@ typedef struct dt_uprobe { char *fn; uint64_t off; int flags; + dt_usdt_arg_t uargs[DT_USDT_MAX_ARGS]; tp_probe_t *tp; int argc; /* number of args */ dt_argdesc_t *args; /* args array (points into argvbuf) */ @@ -651,7 +653,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, pd.prb = prb; dt_dprintf("Providing underlying probe %s:%s:%s:%s @ %lx\n", psp->pps_prv, - psp->pps_mod, psp->pps_fn, psp->pps_prb, psp->pps_off); + psp->pps_mod, psp->pps_fun, psp->pps_prb, psp->pps_off); uprp = dt_probe_lookup(dtp, &pd); if (uprp == NULL) { dt_provider_t *pvp; @@ -671,6 +673,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, upp->off = psp->pps_off; upp->fn = strdup(psp->pps_fn); upp->tp = dt_tp_alloc(dtp); + memcpy(&upp->uargs, psp->pps_uargs, sizeof(upp->uargs)); if (upp->tp == NULL) goto fail; @@ -702,11 +705,11 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, break; case DTPPT_USDT: upp->flags |= PP_IS_USDT; + if (psp->pps_nuargs) + upp->flags |= PP_IS_USDT_NOTE; + break; + default: break; - default: ; - /* - * No flags needed for other types. - */ } return uprp; @@ -973,8 +976,10 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) /* 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); + else if (upp->flags & PP_IS_USDT_NOTE) + dt_cg_tramp_copy_args_from_usdt_spec(pcb, upp->uargs); + else + dt_cg_tramp_copy_args_from_regs(pcb, 0); /* * Apply arg mappings, if needed. -- 2.43.5 From alan.maguire at oracle.com Wed Jan 29 14:55:20 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Wed, 29 Jan 2025 14:55:20 +0000 Subject: [DTrace-devel] [PATCH v2 2/4] selftests/usdt: add test for USDT note-defined probe firing, args In-Reply-To: <20250129145522.512341-1-alan.maguire@oracle.com> References: <20250129145522.512341-1-alan.maguire@oracle.com> Message-ID: <20250129145522.512341-3-alan.maguire@oracle.com> Add test identical to the args tests to verify probe firing and arg retrieval work for USDT notes-defined DTRACE_PROBEn() probes. Need a copy of the sdt.h file which is public domain, so add it in the test directory. Signed-off-by: Alan Maguire --- test/unittest/usdt/sdt_notes.h | 504 +++++++++++++++++++++++++++ test/unittest/usdt/tst.usdt-notes.r | 14 + test/unittest/usdt/tst.usdt-notes.sh | 121 +++++++ 3 files changed, 639 insertions(+) create mode 100644 test/unittest/usdt/sdt_notes.h create mode 100644 test/unittest/usdt/tst.usdt-notes.r create mode 100755 test/unittest/usdt/tst.usdt-notes.sh diff --git a/test/unittest/usdt/sdt_notes.h b/test/unittest/usdt/sdt_notes.h new file mode 100644 index 00000000..ec5423e2 --- /dev/null +++ b/test/unittest/usdt/sdt_notes.h @@ -0,0 +1,504 @@ +/* - Systemtap static probe definition macros. + + This file is dedicated to the public domain, pursuant to CC0 + (https://creativecommons.org/publicdomain/zero/1.0/) +*/ + +#ifndef _SYS_SDT_H +#define _SYS_SDT_H 1 + +/* + This file defines a family of macros + + STAP_PROBEn(op1, ..., opn) + + that emit a nop into the instruction stream, and some data into an auxiliary + note section. The data in the note section describes the operands, in terms + of size and location. Each location is encoded as assembler operand string. + Consumer tools such as gdb or systemtap insert breakpoints on top of + the nop, and decode the location operand-strings, like an assembler, + to find the values being passed. + + The operand strings are selected by the compiler for each operand. + They are constrained by gcc inline-assembler codes. The default is: + + #define STAP_SDT_ARG_CONSTRAINT nor + + This is a good default if the operands tend to be integral and + moderate in number (smaller than number of registers). In other + cases, the compiler may report "'asm' requires impossible reload" or + similar. In this case, consider simplifying the macro call (fewer + and simpler operands), reduce optimization, or override the default + constraints string via: + + #define STAP_SDT_ARG_CONSTRAINT g + #include + + See also: + https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation + https://gcc.gnu.org/onlinedocs/gcc/Constraints.html + */ + + + +#ifdef __ASSEMBLER__ +# define _SDT_PROBE(provider, name, n, arglist) \ + _SDT_ASM_BODY(provider, name, _SDT_ASM_SUBSTR_1, (_SDT_DEPAREN_##n arglist)) \ + _SDT_ASM_BASE +# define _SDT_ASM_1(x) x; +# define _SDT_ASM_2(a, b) a,b; +# define _SDT_ASM_3(a, b, c) a,b,c; +# define _SDT_ASM_5(a, b, c, d, e) a,b,c,d,e; +# define _SDT_ASM_STRING_1(x) .asciz #x; +# define _SDT_ASM_SUBSTR_1(x) .ascii #x; +# define _SDT_DEPAREN_0() /* empty */ +# define _SDT_DEPAREN_1(a) a +# define _SDT_DEPAREN_2(a,b) a b +# define _SDT_DEPAREN_3(a,b,c) a b c +# define _SDT_DEPAREN_4(a,b,c,d) a b c d +# define _SDT_DEPAREN_5(a,b,c,d,e) a b c d e +# define _SDT_DEPAREN_6(a,b,c,d,e,f) a b c d e f +# define _SDT_DEPAREN_7(a,b,c,d,e,f,g) a b c d e f g +# define _SDT_DEPAREN_8(a,b,c,d,e,f,g,h) a b c d e f g h +# define _SDT_DEPAREN_9(a,b,c,d,e,f,g,h,i) a b c d e f g h i +# define _SDT_DEPAREN_10(a,b,c,d,e,f,g,h,i,j) a b c d e f g h i j +# define _SDT_DEPAREN_11(a,b,c,d,e,f,g,h,i,j,k) a b c d e f g h i j k +# define _SDT_DEPAREN_12(a,b,c,d,e,f,g,h,i,j,k,l) a b c d e f g h i j k l +#else +#if defined _SDT_HAS_SEMAPHORES +#define _SDT_NOTE_SEMAPHORE_USE(provider, name) \ + __asm__ __volatile__ ("" :: "m" (provider##_##name##_semaphore)); +#else +#define _SDT_NOTE_SEMAPHORE_USE(provider, name) +#endif + +# define _SDT_PROBE(provider, name, n, arglist) \ + do { \ + _SDT_NOTE_SEMAPHORE_USE(provider, name); \ + __asm__ __volatile__ (_SDT_ASM_BODY(provider, name, _SDT_ASM_ARGS, (n)) \ + :: _SDT_ASM_OPERANDS_##n arglist); \ + __asm__ __volatile__ (_SDT_ASM_BASE); \ + } while (0) +# define _SDT_S(x) #x +# define _SDT_ASM_1(x) _SDT_S(x) "\n" +# define _SDT_ASM_2(a, b) _SDT_S(a) "," _SDT_S(b) "\n" +# define _SDT_ASM_3(a, b, c) _SDT_S(a) "," _SDT_S(b) "," \ + _SDT_S(c) "\n" +# define _SDT_ASM_5(a, b, c, d, e) _SDT_S(a) "," _SDT_S(b) "," \ + _SDT_S(c) "," _SDT_S(d) "," \ + _SDT_S(e) "\n" +# define _SDT_ASM_ARGS(n) _SDT_ASM_TEMPLATE_##n +# define _SDT_ASM_STRING_1(x) _SDT_ASM_1(.asciz #x) +# define _SDT_ASM_SUBSTR_1(x) _SDT_ASM_1(.ascii #x) + +# define _SDT_ARGFMT(no) _SDT_ASM_1(_SDT_SIGN %n[_SDT_S##no]) \ + _SDT_ASM_1(_SDT_SIZE %n[_SDT_S##no]) \ + _SDT_ASM_1(_SDT_TYPE %n[_SDT_S##no]) \ + _SDT_ASM_SUBSTR(_SDT_ARGTMPL(_SDT_A##no)) + + +# ifndef STAP_SDT_ARG_CONSTRAINT +# if defined __powerpc__ +# define STAP_SDT_ARG_CONSTRAINT nZr +# elif defined __arm__ +# define STAP_SDT_ARG_CONSTRAINT g +# else +# define STAP_SDT_ARG_CONSTRAINT nor +# endif +# endif + +# define _SDT_STRINGIFY(x) #x +# define _SDT_ARG_CONSTRAINT_STRING(x) _SDT_STRINGIFY(x) +/* _SDT_S encodes the size and type as 0xSSTT which is decoded by the assembler + macros _SDT_SIZE and _SDT_TYPE */ +# define _SDT_ARG(n, x) \ + [_SDT_S##n] "n" ((_SDT_ARGSIGNED (x) ? (int)-1 : 1) * (-(((int) _SDT_ARGSIZE (x)) << 8) + (-(0x7f & __builtin_classify_type (x))))), \ + [_SDT_A##n] _SDT_ARG_CONSTRAINT_STRING (STAP_SDT_ARG_CONSTRAINT) (_SDT_ARGVAL (x)) +#endif +#define _SDT_ASM_STRING(x) _SDT_ASM_STRING_1(x) +#define _SDT_ASM_SUBSTR(x) _SDT_ASM_SUBSTR_1(x) + +#define _SDT_ARGARRAY(x) (__builtin_classify_type (x) == 14 \ + || __builtin_classify_type (x) == 5) + +#ifdef __cplusplus +# define _SDT_ARGSIGNED(x) (!_SDT_ARGARRAY (x) \ + && __sdt_type<__typeof (x)>::__sdt_signed) +# define _SDT_ARGSIZE(x) (_SDT_ARGARRAY (x) \ + ? sizeof (void *) : sizeof (x)) +# define _SDT_ARGVAL(x) (x) + +# include + +template +struct __sdt_type +{ + static const bool __sdt_signed = false; +}; + +#define __SDT_ALWAYS_SIGNED(T) \ +template<> struct __sdt_type { static const bool __sdt_signed = true; }; +#define __SDT_COND_SIGNED(T,CT) \ +template<> struct __sdt_type { static const bool __sdt_signed = ((CT)(-1) < 1); }; +__SDT_ALWAYS_SIGNED(signed char) +__SDT_ALWAYS_SIGNED(short) +__SDT_ALWAYS_SIGNED(int) +__SDT_ALWAYS_SIGNED(long) +__SDT_ALWAYS_SIGNED(long long) +__SDT_ALWAYS_SIGNED(volatile signed char) +__SDT_ALWAYS_SIGNED(volatile short) +__SDT_ALWAYS_SIGNED(volatile int) +__SDT_ALWAYS_SIGNED(volatile long) +__SDT_ALWAYS_SIGNED(volatile long long) +__SDT_ALWAYS_SIGNED(const signed char) +__SDT_ALWAYS_SIGNED(const short) +__SDT_ALWAYS_SIGNED(const int) +__SDT_ALWAYS_SIGNED(const long) +__SDT_ALWAYS_SIGNED(const long long) +__SDT_ALWAYS_SIGNED(const volatile signed char) +__SDT_ALWAYS_SIGNED(const volatile short) +__SDT_ALWAYS_SIGNED(const volatile int) +__SDT_ALWAYS_SIGNED(const volatile long) +__SDT_ALWAYS_SIGNED(const volatile long long) +__SDT_COND_SIGNED(char, char) +__SDT_COND_SIGNED(wchar_t, wchar_t) +__SDT_COND_SIGNED(volatile char, char) +__SDT_COND_SIGNED(volatile wchar_t, wchar_t) +__SDT_COND_SIGNED(const char, char) +__SDT_COND_SIGNED(const wchar_t, wchar_t) +__SDT_COND_SIGNED(const volatile char, char) +__SDT_COND_SIGNED(const volatile wchar_t, wchar_t) +#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) +/* __SDT_COND_SIGNED(char16_t) */ +/* __SDT_COND_SIGNED(char32_t) */ +#endif + +template +struct __sdt_type<__sdt_E[]> : public __sdt_type<__sdt_E *> {}; + +template +struct __sdt_type<__sdt_E[__sdt_N]> : public __sdt_type<__sdt_E *> {}; + +#elif !defined(__ASSEMBLER__) +__extension__ extern unsigned long long __sdt_unsp; +# define _SDT_ARGINTTYPE(x) \ + __typeof (__builtin_choose_expr (((__builtin_classify_type (x) \ + + 3) & -4) == 4, (x), 0U)) +# define _SDT_ARGSIGNED(x) \ + (!__extension__ \ + (__builtin_constant_p ((((unsigned long long) \ + (_SDT_ARGINTTYPE (x)) __sdt_unsp) \ + & ((unsigned long long)1 << (sizeof (unsigned long long) \ + * __CHAR_BIT__ - 1))) == 0) \ + || (_SDT_ARGINTTYPE (x)) -1 > (_SDT_ARGINTTYPE (x)) 0)) +# define _SDT_ARGSIZE(x) \ + (_SDT_ARGARRAY (x) ? sizeof (void *) : sizeof (x)) +# define _SDT_ARGVAL(x) (x) +#endif + +#if defined __powerpc__ || defined __powerpc64__ +# define _SDT_ARGTMPL(id) %I[id]%[id] +#elif defined __i386__ +# define _SDT_ARGTMPL(id) %k[id] /* gcc.gnu.org/PR80115 sourceware.org/PR24541 */ +#else +# define _SDT_ARGTMPL(id) %[id] +#endif + +/* NB: gdb PR24541 highlighted an unspecified corner of the sdt.h + operand note format. + + The named register may be a longer or shorter (!) alias for the + storage where the value in question is found. For example, on + i386, 64-bit value may be put in register pairs, and the register + name stored would identify just one of them. Previously, gcc was + asked to emit the %w[id] (16-bit alias of some registers holding + operands), even when a wider 32-bit value was used. + + Bottom line: the byte-width given before the @ sign governs. If + there is a mismatch between that width and that of the named + register, then a sys/sdt.h note consumer may need to employ + architecture-specific heuristics to figure out where the compiler + has actually put the complete value. +*/ + +#ifdef __LP64__ +# define _SDT_ASM_ADDR .8byte +#else +# define _SDT_ASM_ADDR .4byte +#endif + +/* The ia64 and s390 nop instructions take an argument. */ +#if defined(__ia64__) || defined(__s390__) || defined(__s390x__) +#define _SDT_NOP nop 0 +#else +#define _SDT_NOP nop +#endif + +#define _SDT_NOTE_NAME "stapsdt" +#define _SDT_NOTE_TYPE 3 + +# define _SDT_ASM_AUTOGROUP "?" + +#define _SDT_DEF_MACROS \ + _SDT_ASM_1(.altmacro) \ + _SDT_ASM_1(.macro _SDT_SIGN x) \ + _SDT_ASM_3(.pushsection .note.stapsdt,"","note") \ + _SDT_ASM_1(.iflt \\x) \ + _SDT_ASM_1(.ascii "-") \ + _SDT_ASM_1(.endif) \ + _SDT_ASM_1(.popsection) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_SIZE_ x) \ + _SDT_ASM_3(.pushsection .note.stapsdt,"","note") \ + _SDT_ASM_1(.ascii "\x") \ + _SDT_ASM_1(.popsection) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_SIZE x) \ + _SDT_ASM_1(_SDT_SIZE_ %%((-(-\\x*((-\\x>0)-(-\\x<0))))>>8)) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_TYPE_ x) \ + _SDT_ASM_3(.pushsection .note.stapsdt,"","note") \ + _SDT_ASM_2(.ifc 8,\\x) \ + _SDT_ASM_1(.ascii "f") \ + _SDT_ASM_1(.endif) \ + _SDT_ASM_1(.ascii "@") \ + _SDT_ASM_1(.popsection) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_TYPE x) \ + _SDT_ASM_1(_SDT_TYPE_ %%((\\x)&(0xff))) \ + _SDT_ASM_1(.endm) + +#define _SDT_UNDEF_MACROS \ + _SDT_ASM_1(.purgem _SDT_SIGN) \ + _SDT_ASM_1(.purgem _SDT_SIZE_) \ + _SDT_ASM_1(.purgem _SDT_SIZE) \ + _SDT_ASM_1(.purgem _SDT_TYPE_) \ + _SDT_ASM_1(.purgem _SDT_TYPE) + +#define _SDT_ASM_BODY(provider, name, pack_args, args, ...) \ + _SDT_DEF_MACROS \ + _SDT_ASM_1(990: _SDT_NOP) \ + _SDT_ASM_3( .pushsection .note.stapsdt,_SDT_ASM_AUTOGROUP,"note") \ + _SDT_ASM_1( .balign 4) \ + _SDT_ASM_3( .4byte 992f-991f, 994f-993f, _SDT_NOTE_TYPE) \ + _SDT_ASM_1(991: .asciz _SDT_NOTE_NAME) \ + _SDT_ASM_1(992: .balign 4) \ + _SDT_ASM_1(993: _SDT_ASM_ADDR 990b) \ + _SDT_ASM_1( _SDT_ASM_ADDR _.stapsdt.base) \ + _SDT_SEMAPHORE(provider,name) \ + _SDT_ASM_STRING(provider) \ + _SDT_ASM_STRING(name) \ + pack_args args \ + _SDT_ASM_SUBSTR(\x00) \ + _SDT_UNDEF_MACROS \ + _SDT_ASM_1(994: .balign 4) \ + _SDT_ASM_1( .popsection) + +#define _SDT_ASM_BASE \ + _SDT_ASM_1(.ifndef _.stapsdt.base) \ + _SDT_ASM_5( .pushsection .stapsdt.base,"aG","progbits", \ + .stapsdt.base,comdat) \ + _SDT_ASM_1( .weak _.stapsdt.base) \ + _SDT_ASM_1( .hidden _.stapsdt.base) \ + _SDT_ASM_1( _.stapsdt.base: .space 1) \ + _SDT_ASM_2( .size _.stapsdt.base, 1) \ + _SDT_ASM_1( .popsection) \ + _SDT_ASM_1(.endif) + +#if defined _SDT_HAS_SEMAPHORES +#define _SDT_SEMAPHORE(p,n) \ + _SDT_ASM_1( _SDT_ASM_ADDR p##_##n##_semaphore) +#else +#define _SDT_SEMAPHORE(p,n) _SDT_ASM_1( _SDT_ASM_ADDR 0) +#endif + +#define _SDT_ASM_BLANK _SDT_ASM_SUBSTR(\x20) +#define _SDT_ASM_TEMPLATE_0 /* no arguments */ +#define _SDT_ASM_TEMPLATE_1 _SDT_ARGFMT(1) +#define _SDT_ASM_TEMPLATE_2 _SDT_ASM_TEMPLATE_1 _SDT_ASM_BLANK _SDT_ARGFMT(2) +#define _SDT_ASM_TEMPLATE_3 _SDT_ASM_TEMPLATE_2 _SDT_ASM_BLANK _SDT_ARGFMT(3) +#define _SDT_ASM_TEMPLATE_4 _SDT_ASM_TEMPLATE_3 _SDT_ASM_BLANK _SDT_ARGFMT(4) +#define _SDT_ASM_TEMPLATE_5 _SDT_ASM_TEMPLATE_4 _SDT_ASM_BLANK _SDT_ARGFMT(5) +#define _SDT_ASM_TEMPLATE_6 _SDT_ASM_TEMPLATE_5 _SDT_ASM_BLANK _SDT_ARGFMT(6) +#define _SDT_ASM_TEMPLATE_7 _SDT_ASM_TEMPLATE_6 _SDT_ASM_BLANK _SDT_ARGFMT(7) +#define _SDT_ASM_TEMPLATE_8 _SDT_ASM_TEMPLATE_7 _SDT_ASM_BLANK _SDT_ARGFMT(8) +#define _SDT_ASM_TEMPLATE_9 _SDT_ASM_TEMPLATE_8 _SDT_ASM_BLANK _SDT_ARGFMT(9) +#define _SDT_ASM_TEMPLATE_10 _SDT_ASM_TEMPLATE_9 _SDT_ASM_BLANK _SDT_ARGFMT(10) +#define _SDT_ASM_TEMPLATE_11 _SDT_ASM_TEMPLATE_10 _SDT_ASM_BLANK _SDT_ARGFMT(11) +#define _SDT_ASM_TEMPLATE_12 _SDT_ASM_TEMPLATE_11 _SDT_ASM_BLANK _SDT_ARGFMT(12) +#define _SDT_ASM_OPERANDS_0() [__sdt_dummy] "g" (0) +#define _SDT_ASM_OPERANDS_1(arg1) _SDT_ARG(1, arg1) +#define _SDT_ASM_OPERANDS_2(arg1, arg2) \ + _SDT_ASM_OPERANDS_1(arg1), _SDT_ARG(2, arg2) +#define _SDT_ASM_OPERANDS_3(arg1, arg2, arg3) \ + _SDT_ASM_OPERANDS_2(arg1, arg2), _SDT_ARG(3, arg3) +#define _SDT_ASM_OPERANDS_4(arg1, arg2, arg3, arg4) \ + _SDT_ASM_OPERANDS_3(arg1, arg2, arg3), _SDT_ARG(4, arg4) +#define _SDT_ASM_OPERANDS_5(arg1, arg2, arg3, arg4, arg5) \ + _SDT_ASM_OPERANDS_4(arg1, arg2, arg3, arg4), _SDT_ARG(5, arg5) +#define _SDT_ASM_OPERANDS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ + _SDT_ASM_OPERANDS_5(arg1, arg2, arg3, arg4, arg5), _SDT_ARG(6, arg6) +#define _SDT_ASM_OPERANDS_7(arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + _SDT_ASM_OPERANDS_6(arg1, arg2, arg3, arg4, arg5, arg6), _SDT_ARG(7, arg7) +#define _SDT_ASM_OPERANDS_8(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ + _SDT_ASM_OPERANDS_7(arg1, arg2, arg3, arg4, arg5, arg6, arg7), \ + _SDT_ARG(8, arg8) +#define _SDT_ASM_OPERANDS_9(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) \ + _SDT_ASM_OPERANDS_8(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), \ + _SDT_ARG(9, arg9) +#define _SDT_ASM_OPERANDS_10(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) \ + _SDT_ASM_OPERANDS_9(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), \ + _SDT_ARG(10, arg10) +#define _SDT_ASM_OPERANDS_11(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11) \ + _SDT_ASM_OPERANDS_10(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10), \ + _SDT_ARG(11, arg11) +#define _SDT_ASM_OPERANDS_12(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12) \ + _SDT_ASM_OPERANDS_11(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11), \ + _SDT_ARG(12, arg12) + +/* These macros can be used in C, C++, or assembly code. + In assembly code the arguments should use normal assembly operand syntax. */ + +#define STAP_PROBE(provider, name) \ + _SDT_PROBE(provider, name, 0, ()) +#define STAP_PROBE1(provider, name, arg1) \ + _SDT_PROBE(provider, name, 1, (arg1)) +#define STAP_PROBE2(provider, name, arg1, arg2) \ + _SDT_PROBE(provider, name, 2, (arg1, arg2)) +#define STAP_PROBE3(provider, name, arg1, arg2, arg3) \ + _SDT_PROBE(provider, name, 3, (arg1, arg2, arg3)) +#define STAP_PROBE4(provider, name, arg1, arg2, arg3, arg4) \ + _SDT_PROBE(provider, name, 4, (arg1, arg2, arg3, arg4)) +#define STAP_PROBE5(provider, name, arg1, arg2, arg3, arg4, arg5) \ + _SDT_PROBE(provider, name, 5, (arg1, arg2, arg3, arg4, arg5)) +#define STAP_PROBE6(provider, name, arg1, arg2, arg3, arg4, arg5, arg6) \ + _SDT_PROBE(provider, name, 6, (arg1, arg2, arg3, arg4, arg5, arg6)) +#define STAP_PROBE7(provider, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + _SDT_PROBE(provider, name, 7, (arg1, arg2, arg3, arg4, arg5, arg6, arg7)) +#define STAP_PROBE8(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) \ + _SDT_PROBE(provider, name, 8, (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) +#define STAP_PROBE9(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\ + _SDT_PROBE(provider, name, 9, (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)) +#define STAP_PROBE10(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) \ + _SDT_PROBE(provider, name, 10, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)) +#define STAP_PROBE11(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11) \ + _SDT_PROBE(provider, name, 11, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)) +#define STAP_PROBE12(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12) \ + _SDT_PROBE(provider, name, 12, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)) + +/* This STAP_PROBEV macro can be used in variadic scenarios, where the + number of probe arguments is not known until compile time. Since + variadic macro support may vary with compiler options, you must + pre-#define SDT_USE_VARIADIC to enable this type of probe. + + The trick to count __VA_ARGS__ was inspired by this post by + Laurent Deniau : + http://groups.google.com/group/comp.std.c/msg/346fc464319b1ee5 + + Note that our _SDT_NARG is called with an extra 0 arg that's not + counted, so we don't have to worry about the behavior of macros + called without any arguments. */ + +#define _SDT_NARG(...) __SDT_NARG(__VA_ARGS__, 12,11,10,9,8,7,6,5,4,3,2,1,0) +#define __SDT_NARG(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12, N, ...) N +#ifdef SDT_USE_VARIADIC +#define _SDT_PROBE_N(provider, name, N, ...) \ + _SDT_PROBE(provider, name, N, (__VA_ARGS__)) +#define STAP_PROBEV(provider, name, ...) \ + _SDT_PROBE_N(provider, name, _SDT_NARG(0, ##__VA_ARGS__), ##__VA_ARGS__) +#endif + +/* These macros are for use in asm statements. You must compile + with -std=gnu99 or -std=c99 to use the STAP_PROBE_ASM macro. + + The STAP_PROBE_ASM macro generates a quoted string to be used in the + template portion of the asm statement, concatenated with strings that + contain the actual assembly code around the probe site. + + For example: + + asm ("before\n" + STAP_PROBE_ASM(provider, fooprobe, %eax 4(%esi)) + "after"); + + emits the assembly code for "before\nafter", with a probe in between. + The probe arguments are the %eax register, and the value of the memory + word located 4 bytes past the address in the %esi register. Note that + because this is a simple asm, not a GNU C extended asm statement, these + % characters do not need to be doubled to generate literal %reg names. + + In a GNU C extended asm statement, the probe arguments can be specified + using the macro STAP_PROBE_ASM_TEMPLATE(n) for n arguments. The paired + macro STAP_PROBE_ASM_OPERANDS gives the C values of these probe arguments, + and appears in the input operand list of the asm statement. For example: + + asm ("someinsn %0,%1\n" // %0 is output operand, %1 is input operand + STAP_PROBE_ASM(provider, fooprobe, STAP_PROBE_ASM_TEMPLATE(3)) + "otherinsn %[namedarg]" + : "r" (outvar) + : "g" (some_value), [namedarg] "i" (1234), + STAP_PROBE_ASM_OPERANDS(3, some_value, some_ptr->field, 1234)); + + This is just like writing: + + STAP_PROBE3(provider, fooprobe, some_value, some_ptr->field, 1234)); + + but the probe site is right between "someinsn" and "otherinsn". + + The probe arguments in STAP_PROBE_ASM can be given as assembly + operands instead, even inside a GNU C extended asm statement. + Note that these can use operand templates like %0 or %[name], + and likewise they must write %%reg for a literal operand of %reg. */ + +#define _SDT_ASM_BODY_1(p,n,...) _SDT_ASM_BODY(p,n,_SDT_ASM_SUBSTR,(__VA_ARGS__)) +#define _SDT_ASM_BODY_2(p,n,...) _SDT_ASM_BODY(p,n,/*_SDT_ASM_STRING */,__VA_ARGS__) +#define _SDT_ASM_BODY_N2(p,n,no,...) _SDT_ASM_BODY_ ## no(p,n,__VA_ARGS__) +#define _SDT_ASM_BODY_N1(p,n,no,...) _SDT_ASM_BODY_N2(p,n,no,__VA_ARGS__) +#define _SDT_ASM_BODY_N(p,n,...) _SDT_ASM_BODY_N1(p,n,_SDT_NARG(0, __VA_ARGS__),__VA_ARGS__) + +#if __STDC_VERSION__ >= 199901L +# define STAP_PROBE_ASM(provider, name, ...) \ + _SDT_ASM_BODY_N(provider, name, __VA_ARGS__) \ + _SDT_ASM_BASE +# define STAP_PROBE_ASM_OPERANDS(n, ...) _SDT_ASM_OPERANDS_##n(__VA_ARGS__) +#else +# define STAP_PROBE_ASM(provider, name, args) \ + _SDT_ASM_BODY(provider, name, /* _SDT_ASM_STRING */, (args)) \ + _SDT_ASM_BASE +#endif +#define STAP_PROBE_ASM_TEMPLATE(n) _SDT_ASM_TEMPLATE_##n,"use _SDT_ASM_TEMPLATE_" + + +/* DTrace compatible macro names. */ +#define DTRACE_PROBE(provider,probe) \ + STAP_PROBE(provider,probe) +#define DTRACE_PROBE1(provider,probe,parm1) \ + STAP_PROBE1(provider,probe,parm1) +#define DTRACE_PROBE2(provider,probe,parm1,parm2) \ + STAP_PROBE2(provider,probe,parm1,parm2) +#define DTRACE_PROBE3(provider,probe,parm1,parm2,parm3) \ + STAP_PROBE3(provider,probe,parm1,parm2,parm3) +#define DTRACE_PROBE4(provider,probe,parm1,parm2,parm3,parm4) \ + STAP_PROBE4(provider,probe,parm1,parm2,parm3,parm4) +#define DTRACE_PROBE5(provider,probe,parm1,parm2,parm3,parm4,parm5) \ + STAP_PROBE5(provider,probe,parm1,parm2,parm3,parm4,parm5) +#define DTRACE_PROBE6(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6) \ + STAP_PROBE6(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6) +#define DTRACE_PROBE7(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7) \ + STAP_PROBE7(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7) +#define DTRACE_PROBE8(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) \ + STAP_PROBE8(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) +#define DTRACE_PROBE9(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) \ + STAP_PROBE9(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) +#define DTRACE_PROBE10(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) \ + STAP_PROBE10(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) +#define DTRACE_PROBE11(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11) \ + STAP_PROBE11(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11) +#define DTRACE_PROBE12(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11,parm12) \ + STAP_PROBE12(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11,parm12) + + +#endif /* sys/sdt.h */ diff --git a/test/unittest/usdt/tst.usdt-notes.r b/test/unittest/usdt/tst.usdt-notes.r new file mode 100644 index 00000000..db6d18cb --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes.r @@ -0,0 +1,14 @@ +test:main:zero +test:main:one:1 +test:main:two:2:3 +test:main:three:4:5:7 +test:main:four:7:8:9:10 +test:main:five:11:12:13:14:15 +test:main:six:16:17:18:19:20:21 +test:main:seven:22:23:24:25:26:27:28 +test:main:eight:29:30:31:32:33:34:35:36 +test:main:nine:37:38:39:40:41:42:43:44:45 +test:main:ten:46:47:48:49:50:51:52:53:54:55 +test:main:eleven:56:57:58:59:60:61:62:63:64:65 +test:main:twelve:67:68:69:70:71:72:73:74:75:76 + diff --git a/test/unittest/usdt/tst.usdt-notes.sh b/test/unittest/usdt/tst.usdt-notes.sh new file mode 100755 index 00000000..364ba8db --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes.sh @@ -0,0 +1,121 @@ +#!/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 covers all USDT probes fired by the DTRACE_PROBEn macros. +# Arguments values are checked only for first 10 arguments because +# there is support for arg0 ... arg9 only at this moment. + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="-I${PWD}/test/unittest/usdt" + +DIRNAME="$tmpdir/usdt-notes.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > test.c < + +int +main(int argc, char **argv) +{ + DTRACE_PROBE(test_prov, zero); + DTRACE_PROBE1(test_prov, one, argc); + DTRACE_PROBE2(test_prov, two, 2, 3); + DTRACE_PROBE3(test_prov, three, 4, 5, 7); + DTRACE_PROBE4(test_prov, four, 7, 8, 9, 10); + DTRACE_PROBE5(test_prov, five, 11, 12, 13, 14, 15); + DTRACE_PROBE6(test_prov, six, 16, 17, 18, 19, 20, 21); + DTRACE_PROBE7(test_prov, seven, 22, 23, 24, 25, 26, 27, 28); + DTRACE_PROBE8(test_prov, eight, 29, 30, 31, 32, 33, 34, 35, 36); + DTRACE_PROBE9(test_prov, nine, 37, 38, 39, 40, 41, 42, 43, 44, 45); + DTRACE_PROBE10(test_prov, ten, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55); + DTRACE_PROBE11(test_prov, eleven, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66); + DTRACE_PROBE12(test_prov, twelve, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78); +} +EOF + +${CC} ${CFLAGS} -o test test.c +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi + +$dtrace -c ./test -qs /dev/stdin < References: <20250129145522.512341-1-alan.maguire@oracle.com> Message-ID: <20250129145522.512341-4-alan.maguire@oracle.com> To ensure USDT notes are found/fire for shared libraries, create a shared library and trace the USDT probes in it. To ensure the library is loaded when DTrace has started, call it early in the program lifetime and sleep until DTrace starts; at that point trace the probes with the pid and ensure they fire with expected args. Signed-off-by: Alan Maguire --- test/unittest/usdt/tst.usdt-notes-lib.r | 14 +++ test/unittest/usdt/tst.usdt-notes-lib.sh | 145 +++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 test/unittest/usdt/tst.usdt-notes-lib.r create mode 100755 test/unittest/usdt/tst.usdt-notes-lib.sh diff --git a/test/unittest/usdt/tst.usdt-notes-lib.r b/test/unittest/usdt/tst.usdt-notes-lib.r new file mode 100644 index 00000000..cab7b6d5 --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes-lib.r @@ -0,0 +1,14 @@ +libusdttest.so:libfn:zero +libusdttest.so:libfn:one:1 +libusdttest.so:libfn:two:2:3 +libusdttest.so:libfn:three:4:5:7 +libusdttest.so:libfn:four:7:8:9:10 +libusdttest.so:libfn:five:11:12:13:14:15 +libusdttest.so:libfn:six:16:17:18:19:20:21 +libusdttest.so:libfn:seven:22:23:24:25:26:27:28 +libusdttest.so:libfn:eight:29:30:31:32:33:34:35:36 +libusdttest.so:libfn:nine:37:38:39:40:41:42:43:44:45 +libusdttest.so:libfn:ten:46:47:48:49:50:51:52:53:54:55 +libusdttest.so:libfn:eleven:56:57:58:59:60:61:62:63:64:65 +libusdttest.so:libfn:twelve:67:68:69:70:71:72:73:74:75:76 + diff --git a/test/unittest/usdt/tst.usdt-notes-lib.sh b/test/unittest/usdt/tst.usdt-notes-lib.sh new file mode 100755 index 00000000..ed87e9f5 --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes-lib.sh @@ -0,0 +1,145 @@ +#!/bin/bash +# +# Oracle Linux DTrace. +# Copyright (c) 2025, 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 covers all USDT probes fired by the DTRACE_PROBEn macros. +# Arguments values are checked only for first 10 arguments because +# there is support for arg0 ... arg9 only at this moment. + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="-I${PWD}/test/unittest/usdt" + +DIRNAME="$tmpdir/usdt-notes.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > libusdttest.c < + +void +libfn(int argc, char **argv) +{ + if (argc == 0 && argv == 0) + return; + DTRACE_PROBE(test_prov, zero); + DTRACE_PROBE1(test_prov, one, argc); + DTRACE_PROBE2(test_prov, two, 2, 3); + DTRACE_PROBE3(test_prov, three, 4, 5, 7); + DTRACE_PROBE4(test_prov, four, 7, 8, 9, 10); + DTRACE_PROBE5(test_prov, five, 11, 12, 13, 14, 15); + DTRACE_PROBE6(test_prov, six, 16, 17, 18, 19, 20, 21); + DTRACE_PROBE7(test_prov, seven, 22, 23, 24, 25, 26, 27, 28); + DTRACE_PROBE8(test_prov, eight, 29, 30, 31, 32, 33, 34, 35, 36); + DTRACE_PROBE9(test_prov, nine, 37, 38, 39, 40, 41, 42, 43, 44, 45); + DTRACE_PROBE10(test_prov, ten, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55); + DTRACE_PROBE11(test_prov, eleven, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66); + DTRACE_PROBE12(test_prov, twelve, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78); +} +EOF + +cat > test.c < + +extern void libfn(int argc, char **argv); + +int +main(int argc, char **argv) +{ + libfn(0, 0); + sleep(10); + libfn(argc, argv); + return 0; +} +EOF + +${CC} ${CFLAGS} -c -fpic libusdttest.c +${CC} -shared -o libusdttest.so libusdttest.o +${CC} -L. ${CFLAGS} -o test test.c -lusdttest +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi + +export LD_LIBRARY_PATH=.:${LD_LIBRARY_PATH} +LD_LIBRARY_PATH=.:${LD_LIBRARY_PATH} ./test & +PID=$! +sleep 5 +$dtrace -p $PID -qs /dev/stdin < References: <20250129145522.512341-1-alan.maguire@oracle.com> Message-ID: <20250129145522.512341-5-alan.maguire@oracle.com> Add a test exercising various arg types supported by USDT notes; register values, register + offset and constants. The test generates a binary with probes represented as follows on x86_64: Displaying notes found in: .note.stapsdt Owner Data size Description stapsdt 0x00000048 NT_STAPSDT (SystemTap probe descriptors) Provider: test_prov Name: args Location: 0x0000000000400557, Base: 0x00000000004005f8, Semaphore: 0x0000000000000000 Arguments: -4 at -4(%rbp) 8@%rax 8@%rdx -4@$18 Verify we get expected data for the probe arguments. Signed-off-by: Alan Maguire --- test/unittest/usdt/tst.usdt-notes-args.r | 2 + test/unittest/usdt/tst.usdt-notes-args.sh | 51 +++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 test/unittest/usdt/tst.usdt-notes-args.r create mode 100755 test/unittest/usdt/tst.usdt-notes-args.sh diff --git a/test/unittest/usdt/tst.usdt-notes-args.r b/test/unittest/usdt/tst.usdt-notes-args.r new file mode 100644 index 00000000..42bca19f --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes-args.r @@ -0,0 +1,2 @@ +test:main:args:2:./test:val:18 + diff --git a/test/unittest/usdt/tst.usdt-notes-args.sh b/test/unittest/usdt/tst.usdt-notes-args.sh new file mode 100755 index 00000000..7c8ea37b --- /dev/null +++ b/test/unittest/usdt/tst.usdt-notes-args.sh @@ -0,0 +1,51 @@ +#!/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 covers all USDT probes fired by the DTRACE_PROBEn macros. +# Arguments values are checked only for first 10 arguments because +# there is support for arg0 ... arg9 only at this moment. + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="-I${PWD}/test/unittest/usdt" + +DIRNAME="$tmpdir/usdt-notes.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > test.c < + +int +main(int argc, char **argv) +{ + DTRACE_PROBE4(test_prov, args, argc, argv[0], argv[1] + 4, 18); +} +EOF + +${CC} ${CFLAGS} -o test test.c +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi + +$dtrace -c './test arg1val' -qs /dev/stdin < References: <20250129144401.505186-1-alan.maguire@oracle.com> Message-ID: apologies - changes that should have been in patch 1 were included in patch 4; I've fixed this and sent a v2 [1]. Thanks! Alan [1] https://lore.kernel.org/dtrace/20250129145522.512341-1-alan.maguire at oracle.com/ On 29/01/2025 14:43, Alan Maguire wrote: > This series adds support (patch 1) for ELF-note defined USDT > probes in binaries and libraries; patches 2-4 add tests. > > Basic pid-specific USDT support is added; i.e. it is necessary > to specify the target pid in the provider name such as > "example1234" ; future work could add pid wildcarding. > > ELF note defined probes are defined by including sys/sdt.h > from the systemtap-sdt-devel package, and are defined in > C programs via > > DTRACE_PROBEn(provider, probe, [args...]) > > See the tests for concrete examples. > > For python, go, etc, USDT probes can be added via libstapsdt [1] > and associated language-specific bindings. This allows users > of those languages to add USDT probes too. For example, the > following example program adds a "pythonapp" probe "firstProbe" > using the python-specific libstapsdt binding: > > #!/usr/bin/python3 > from time import sleep > import stapsdt > provider = stapsdt.Provider("pythonapp") > probe = provider.add_probe( > "firstProbe", stapsdt.ArgTypes.uint64, stapsdt.ArgTypes.int32) > provider.load() > while True: > print("Firing probe...") > if probe.fire("My little probe", 42): > print("Probe fired!") > sleep(1) > > We can then trace this via dtrace: > > # dtrace -n 'pythonapp503211:::* { printf("args %s, %d\n", copyinstr(arg0), arg1); }' > > dtrace: description 'pythonapp503211:::* ' matched 1 probe > CPU ID FUNCTION:NAME > 6 286628 :firstProbe args My little probe, 42 > > [1] https://github.com/linux-usdt/libstapsdt > > Alan Maguire (4): > USDT: support ELF-note-defined probes > selftests/usdt: add test for USDT note-defined probe firing, args > selftests/usdt: add test for USDT notes in shared library > selftests/usdt: add test covering different forms of USDT note args > > include/dtrace/pid.h | 29 ++ > libdtrace/dt_cg.c | 47 ++ > libdtrace/dt_cg.h | 1 + > libdtrace/dt_pid.c | 466 ++++++++++++++++++++ > libdtrace/dt_prov_uprobe.c | 19 +- > test/unittest/usdt/sdt_notes.h | 504 ++++++++++++++++++++++ > test/unittest/usdt/tst.usdt-notes-args.r | 2 + > test/unittest/usdt/tst.usdt-notes-args.sh | 51 +++ > test/unittest/usdt/tst.usdt-notes-lib.r | 14 + > test/unittest/usdt/tst.usdt-notes-lib.sh | 145 +++++++ > test/unittest/usdt/tst.usdt-notes.r | 14 + > test/unittest/usdt/tst.usdt-notes.sh | 121 ++++++ > 12 files changed, 1406 insertions(+), 7 deletions(-) > create mode 100644 test/unittest/usdt/sdt_notes.h > create mode 100644 test/unittest/usdt/tst.usdt-notes-args.r > create mode 100755 test/unittest/usdt/tst.usdt-notes-args.sh > create mode 100644 test/unittest/usdt/tst.usdt-notes-lib.r > create mode 100755 test/unittest/usdt/tst.usdt-notes-lib.sh > create mode 100644 test/unittest/usdt/tst.usdt-notes.r > create mode 100755 test/unittest/usdt/tst.usdt-notes.sh > From kris.van.hees at oracle.com Wed Jan 29 15:33:39 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Wed, 29 Jan 2025 10:33:39 -0500 Subject: [DTrace-devel] [PATCH v2 0/4] ELF note-based USDT support In-Reply-To: <20250129145522.512341-1-alan.maguire@oracle.com> References: <20250129145522.512341-1-alan.maguire@oracle.com> Message-ID: Thank you for rebasing your work on the newest tree. That will certainly help review them and move things forward. I would definitely rework the commit message though, because 1. DTrace has a specific understanding of what USDT probes are and how they work and stap-based probes do not provide the same functionality. One example of that you already point ay: they are not discoverable - i.e. they are not registered upon startup which is why you need to refer to them directly by provider name (with embedded pid). I think you need to be very clear about the distinction. Using STAPSDT or stapsdt might be a better choice than referring to USDT. 2. I think that the commit message fails to highlight that this support is to make it possible to trace programs (and shared librearies)that have been built with stap style probes. I don't think it is in the best interest of DTrace users to build their executables and shared libraries with stap style probes over DTrace USDT probes, especially given the significant advantage that DTrace USDT probes have (see 1. above). 3. While I can see the point of mentioning how to add stapsdt probes to code, it also is a source for confusion and thus is probably better left out. Since this is a compability feature, surely those wanting to use it already have executables with such probes or know how to create them. By including it here, you also introduce the very unfortunate fact that stapsdt uses DTRACE_PROBE*() macros even though the probes have never really been DTrace compatible, and it is only with your proposed patch now that they could be used in DTrace. The systemtap project shouldn't have piggy-backed on DTRACE_PROBE*() in the first place because it causes this type of confusion and complications, so I would very much prefer not to highlight that mess with this patch series. The stap probe support is very significant because we unfortunately do have to live with a world where there are multiple ways that such userspace probes have been implemented. And given that packages are released with probes and people may want to trace them makes this addition certainly very worthwhile. But I think it should be clear that this is for compatibilty/interoperability purposes only. Kris On Wed, Jan 29, 2025 at 02:55:18PM +0000, Alan Maguire wrote: > This series adds support (patch 1) for ELF-note defined USDT > probes in binaries and libraries; patches 2-4 add tests. > > Basic pid-specific USDT support is added; i.e. it is necessary > to specify the target pid in the provider name such as > "example1234" ; future work could add pid wildcarding. > > ELF note defined probes are defined by including sys/sdt.h > from the systemtap-sdt-devel package, and are defined in > C programs via > > DTRACE_PROBEn(provider, probe, [args...]) > > See the tests for concrete examples. > > For python, go, etc, USDT probes can be added via libstapsdt [1] > and associated language-specific bindings. This allows users > of those languages to add USDT probes too. For example, the > following example program adds a "pythonapp" probe "firstProbe" > using the python-specific libstapsdt binding: > > #!/usr/bin/python3 > from time import sleep > import stapsdt > provider = stapsdt.Provider("pythonapp") > probe = provider.add_probe( > "firstProbe", stapsdt.ArgTypes.uint64, stapsdt.ArgTypes.int32) > provider.load() > while True: > print("Firing probe...") > if probe.fire("My little probe", 42): > print("Probe fired!") > sleep(1) > > We can then trace this via dtrace: > > # dtrace -n 'pythonapp503211:::* { printf("args %s, %d\n", copyinstr(arg0), arg1); }' > > dtrace: description 'pythonapp503211:::* ' matched 1 probe > CPU ID FUNCTION:NAME > 6 286628 :firstProbe args My little probe, 42 > > [1] https://github.com/linux-usdt/libstapsdt > > Alan Maguire (4): > USDT: support ELF-note-defined probes > selftests/usdt: add test for USDT note-defined probe firing, args > selftests/usdt: add test for USDT notes in shared library > selftests/usdt: add test covering different forms of USDT note args > > include/dtrace/pid.h | 29 ++ > libdtrace/dt_cg.c | 47 ++ > libdtrace/dt_cg.h | 1 + > libdtrace/dt_pid.c | 466 ++++++++++++++++++++ > libdtrace/dt_prov_uprobe.c | 19 +- > test/unittest/usdt/sdt_notes.h | 504 ++++++++++++++++++++++ > test/unittest/usdt/tst.usdt-notes-args.r | 2 + > test/unittest/usdt/tst.usdt-notes-args.sh | 51 +++ > test/unittest/usdt/tst.usdt-notes-lib.r | 14 + > test/unittest/usdt/tst.usdt-notes-lib.sh | 145 +++++++ > test/unittest/usdt/tst.usdt-notes.r | 14 + > test/unittest/usdt/tst.usdt-notes.sh | 121 ++++++ > 12 files changed, 1406 insertions(+), 7 deletions(-) > create mode 100644 test/unittest/usdt/sdt_notes.h > create mode 100644 test/unittest/usdt/tst.usdt-notes-args.r > create mode 100755 test/unittest/usdt/tst.usdt-notes-args.sh > create mode 100644 test/unittest/usdt/tst.usdt-notes-lib.r > create mode 100755 test/unittest/usdt/tst.usdt-notes-lib.sh > create mode 100644 test/unittest/usdt/tst.usdt-notes.r > create mode 100755 test/unittest/usdt/tst.usdt-notes.sh > > -- > 2.43.5 > From eugene.loh at oracle.com Thu Jan 30 03:59:22 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Wed, 29 Jan 2025 22:59:22 -0500 Subject: [DTrace-devel] [PATCH 5/6] procfs: add 'execargs' global variable as inline In-Reply-To: References: <9164adb5-a6b1-a7ff-530c-6aa30fa57be3@oracle.com> Message-ID: <58ef1fad-97fb-c907-cc0b-fd29de5a58dc@oracle.com> Is d_execargs() supposed to be user callable?? Is it supposed to be a documented feature?? Should it be tested?? What should happen if it is used in a user's D script? On 1/29/25 01:45, Kris Van Hees wrote: > Actually, I am withdrawing this patch. I forgot that we have curpsinfo as a > builtin, so execargs can be obtained as curpsinfo->pr_psargs, so there is no > need for a shorthand. > > On Tue, Jan 28, 2025 at 09:56:17PM -0500, Kris Van Hees wrote: >> On Tue, Jan 28, 2025 at 07:53:51PM -0500, Eugene Loh wrote: >>> I'd like a little more context here. >>> >>> Features:? There is a new execargs global variable.? I take it this is new >>> to D or an extension to the D language?? Would it make sense to call this a >>> built-in variable?? Are we also exposing a new function d_execargs()? >>> Shouldn't there be tests for using execargs or d_execargs() in scripts?? I >>> cannot tell if we are adding new user features (which should be tested) or >>> not. >> Yes, execargs is essentially a new built-in variable. It is defined as an >> inline, simply doing d_execargs(curthread), so it is a short-hand to get to >> the pr_psargs info for the current task. >> >> So it depends 100% on the d_execargs() implementation, which is a function >> that I added in order to implement the psinfo->pr_psargs translator >> functionality. >> >>> Testing:? I see that the following patch (6/6) lifts some XFAILs on some >>> pr_psargs tests.? Should tst.psinfo.d be added to them? And should the >>> removal of XFAIL for test/unittest/builtinvar/tst.psinfo-bug21974606.d be >>> moved from that patch to this one?? And should there be correctness checks >>> for this output:? not simply "does this script not blow up?" but actually >>> "does this script produce correct or even just sensible output?"? >> None of the existing tests should be moved here because they do not use the >> ezecargs variable (since it is new). I'll add a few tests for this built-in >> specifically. I'd be happy to even drop this patch and not add a new >> built-in, but it seems somehow odd not to provide it. >> >>> I'll look more but am certainly unclear if we're talking new D features here >>> (and if so, why they're not tested). >>> On 1/28/25 01:31, Kris Van Hees wrote: >>> >>>> The 'execargs' global variable provides the psargs for curthread. >>>> >>>> Signed-off-by: Kris Van Hees >>>> --- >>>> dlibs/aarch64/5.11/procfs.d | 4 ++++ >>>> dlibs/aarch64/5.12/procfs.d | 4 ++++ >>>> dlibs/aarch64/5.14/procfs.d | 4 ++++ >>>> dlibs/aarch64/5.16/procfs.d | 4 ++++ >>>> dlibs/aarch64/5.2/procfs.d | 4 ++++ >>>> dlibs/aarch64/5.6/procfs.d | 4 ++++ >>>> dlibs/aarch64/6.1/procfs.d | 4 ++++ >>>> dlibs/aarch64/6.10/procfs.d | 4 ++++ >>>> dlibs/x86_64/5.11/procfs.d | 4 ++++ >>>> dlibs/x86_64/5.12/procfs.d | 4 ++++ >>>> dlibs/x86_64/5.14/procfs.d | 4 ++++ >>>> dlibs/x86_64/5.16/procfs.d | 4 ++++ >>>> dlibs/x86_64/5.2/procfs.d | 4 ++++ >>>> dlibs/x86_64/5.6/procfs.d | 4 ++++ >>>> dlibs/x86_64/6.1/procfs.d | 4 ++++ >>>> dlibs/x86_64/6.10/procfs.d | 4 ++++ >>>> libdtrace/procfs.d.in | 4 ++++ >>>> 17 files changed, 68 insertions(+) >>>> >>>> diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d >>>> index 70a43ddf..9c06fe1f 100644 >>>> --- a/dlibs/aarch64/5.11/procfs.d >>>> +++ b/dlibs/aarch64/5.11/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d >>>> index 70a43ddf..9c06fe1f 100644 >>>> --- a/dlibs/aarch64/5.12/procfs.d >>>> +++ b/dlibs/aarch64/5.12/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d >>>> index ef27bb70..2824d137 100644 >>>> --- a/dlibs/aarch64/5.14/procfs.d >>>> +++ b/dlibs/aarch64/5.14/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d >>>> index cad2d2c5..daf30745 100644 >>>> --- a/dlibs/aarch64/5.16/procfs.d >>>> +++ b/dlibs/aarch64/5.16/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d >>>> index 6b1b1b9c..3594e5e9 100644 >>>> --- a/dlibs/aarch64/5.2/procfs.d >>>> +++ b/dlibs/aarch64/5.2/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d >>>> index 70a43ddf..9c06fe1f 100644 >>>> --- a/dlibs/aarch64/5.6/procfs.d >>>> +++ b/dlibs/aarch64/5.6/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d >>>> index 4cb7b77c..2d52f079 100644 >>>> --- a/dlibs/aarch64/6.1/procfs.d >>>> +++ b/dlibs/aarch64/6.1/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d >>>> index 4cb7b77c..2d52f079 100644 >>>> --- a/dlibs/aarch64/6.10/procfs.d >>>> +++ b/dlibs/aarch64/6.10/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d >>>> index c2be76d8..7679db2e 100644 >>>> --- a/dlibs/x86_64/5.11/procfs.d >>>> +++ b/dlibs/x86_64/5.11/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d >>>> index c2be76d8..7679db2e 100644 >>>> --- a/dlibs/x86_64/5.12/procfs.d >>>> +++ b/dlibs/x86_64/5.12/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d >>>> index 28fada6d..3a348ebc 100644 >>>> --- a/dlibs/x86_64/5.14/procfs.d >>>> +++ b/dlibs/x86_64/5.14/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d >>>> index cad2d2c5..daf30745 100644 >>>> --- a/dlibs/x86_64/5.16/procfs.d >>>> +++ b/dlibs/x86_64/5.16/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d >>>> index 08696cf7..6ad926ee 100644 >>>> --- a/dlibs/x86_64/5.2/procfs.d >>>> +++ b/dlibs/x86_64/5.2/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d >>>> index c2be76d8..7679db2e 100644 >>>> --- a/dlibs/x86_64/5.6/procfs.d >>>> +++ b/dlibs/x86_64/5.6/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d >>>> index 4cb7b77c..2d52f079 100644 >>>> --- a/dlibs/x86_64/6.1/procfs.d >>>> +++ b/dlibs/x86_64/6.1/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d >>>> index 4cb7b77c..2d52f079 100644 >>>> --- a/dlibs/x86_64/6.10/procfs.d >>>> +++ b/dlibs/x86_64/6.10/procfs.d >>>> @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; >>>> diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in >>>> index e9d50349..827d6b81 100644 >>>> --- a/libdtrace/procfs.d.in >>>> +++ b/libdtrace/procfs.d.in >>>> @@ -307,6 +307,10 @@ inline string root = d_path(&(curthread->fs->root)); >>>> #pragma D attributes Stable/Stable/Common root >>>> #pragma D binding "1.0" root >>>> +inline string execargs = d_execargs(curthread); >>>> +#pragma D attributes Stable/Stable/Common root >>>> +#pragma D binding "2.0" execargs >>>> + >>>> inline int CLD_EXITED = 1; >>>> #pragma D binding "1.0" CLD_EXITED >>>> inline int CLD_KILLED = 2; From kris.van.hees at oracle.com Thu Jan 30 04:46:49 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Wed, 29 Jan 2025 23:46:49 -0500 Subject: [DTrace-devel] [PATCH 5/6] procfs: add 'execargs' global variable as inline In-Reply-To: <58ef1fad-97fb-c907-cc0b-fd29de5a58dc@oracle.com> References: <9164adb5-a6b1-a7ff-530c-6aa30fa57be3@oracle.com> <58ef1fad-97fb-c907-cc0b-fd29de5a58dc@oracle.com> Message-ID: On Wed, Jan 29, 2025 at 10:59:22PM -0500, Eugene Loh wrote: > Is d_execargs() supposed to be user callable?? Is it supposed to be a > documented feature?? Should it be tested?? What should happen if it is used > in a user's D script? I assume you mean this as feedback for the patch that introduces d_execargs rather than this withdrawn patch? Any function that is defined in D (as d_execargs needs to be) can be called by users. Whether it is documented is a matter to discuss with the documentation team, but it certainly can be documented. As long as it is understood that this is a function that exists to support a translator and that its implementation is done in function of that. So e.g. we are not guaranteeing implementation details beyond that. It is tested. If it is used in a user's D script, it will work as expected since it is a regular D function, as one would expect. I am not sure what you mean with your question beyond that. > On 1/29/25 01:45, Kris Van Hees wrote: > > Actually, I am withdrawing this patch. I forgot that we have curpsinfo as a > > builtin, so execargs can be obtained as curpsinfo->pr_psargs, so there is no > > need for a shorthand. > > > > On Tue, Jan 28, 2025 at 09:56:17PM -0500, Kris Van Hees wrote: > > > On Tue, Jan 28, 2025 at 07:53:51PM -0500, Eugene Loh wrote: > > > > I'd like a little more context here. > > > > > > > > Features:? There is a new execargs global variable.? I take it this is new > > > > to D or an extension to the D language?? Would it make sense to call this a > > > > built-in variable?? Are we also exposing a new function d_execargs()? > > > > Shouldn't there be tests for using execargs or d_execargs() in scripts?? I > > > > cannot tell if we are adding new user features (which should be tested) or > > > > not. > > > Yes, execargs is essentially a new built-in variable. It is defined as an > > > inline, simply doing d_execargs(curthread), so it is a short-hand to get to > > > the pr_psargs info for the current task. > > > > > > So it depends 100% on the d_execargs() implementation, which is a function > > > that I added in order to implement the psinfo->pr_psargs translator > > > functionality. > > > > > > > Testing:? I see that the following patch (6/6) lifts some XFAILs on some > > > > pr_psargs tests.? Should tst.psinfo.d be added to them? And should the > > > > removal of XFAIL for test/unittest/builtinvar/tst.psinfo-bug21974606.d be > > > > moved from that patch to this one?? And should there be correctness checks > > > > for this output:? not simply "does this script not blow up?" but actually > > > > "does this script produce correct or even just sensible output?"? > > > None of the existing tests should be moved here because they do not use the > > > ezecargs variable (since it is new). I'll add a few tests for this built-in > > > specifically. I'd be happy to even drop this patch and not add a new > > > built-in, but it seems somehow odd not to provide it. > > > > > > > I'll look more but am certainly unclear if we're talking new D features here > > > > (and if so, why they're not tested). > > > > On 1/28/25 01:31, Kris Van Hees wrote: > > > > > > > > > The 'execargs' global variable provides the psargs for curthread. > > > > > > > > > > Signed-off-by: Kris Van Hees > > > > > --- > > > > > dlibs/aarch64/5.11/procfs.d | 4 ++++ > > > > > dlibs/aarch64/5.12/procfs.d | 4 ++++ > > > > > dlibs/aarch64/5.14/procfs.d | 4 ++++ > > > > > dlibs/aarch64/5.16/procfs.d | 4 ++++ > > > > > dlibs/aarch64/5.2/procfs.d | 4 ++++ > > > > > dlibs/aarch64/5.6/procfs.d | 4 ++++ > > > > > dlibs/aarch64/6.1/procfs.d | 4 ++++ > > > > > dlibs/aarch64/6.10/procfs.d | 4 ++++ > > > > > dlibs/x86_64/5.11/procfs.d | 4 ++++ > > > > > dlibs/x86_64/5.12/procfs.d | 4 ++++ > > > > > dlibs/x86_64/5.14/procfs.d | 4 ++++ > > > > > dlibs/x86_64/5.16/procfs.d | 4 ++++ > > > > > dlibs/x86_64/5.2/procfs.d | 4 ++++ > > > > > dlibs/x86_64/5.6/procfs.d | 4 ++++ > > > > > dlibs/x86_64/6.1/procfs.d | 4 ++++ > > > > > dlibs/x86_64/6.10/procfs.d | 4 ++++ > > > > > libdtrace/procfs.d.in | 4 ++++ > > > > > 17 files changed, 68 insertions(+) > > > > > > > > > > diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d > > > > > index 70a43ddf..9c06fe1f 100644 > > > > > --- a/dlibs/aarch64/5.11/procfs.d > > > > > +++ b/dlibs/aarch64/5.11/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d > > > > > index 70a43ddf..9c06fe1f 100644 > > > > > --- a/dlibs/aarch64/5.12/procfs.d > > > > > +++ b/dlibs/aarch64/5.12/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d > > > > > index ef27bb70..2824d137 100644 > > > > > --- a/dlibs/aarch64/5.14/procfs.d > > > > > +++ b/dlibs/aarch64/5.14/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d > > > > > index cad2d2c5..daf30745 100644 > > > > > --- a/dlibs/aarch64/5.16/procfs.d > > > > > +++ b/dlibs/aarch64/5.16/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d > > > > > index 6b1b1b9c..3594e5e9 100644 > > > > > --- a/dlibs/aarch64/5.2/procfs.d > > > > > +++ b/dlibs/aarch64/5.2/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d > > > > > index 70a43ddf..9c06fe1f 100644 > > > > > --- a/dlibs/aarch64/5.6/procfs.d > > > > > +++ b/dlibs/aarch64/5.6/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d > > > > > index 4cb7b77c..2d52f079 100644 > > > > > --- a/dlibs/aarch64/6.1/procfs.d > > > > > +++ b/dlibs/aarch64/6.1/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d > > > > > index 4cb7b77c..2d52f079 100644 > > > > > --- a/dlibs/aarch64/6.10/procfs.d > > > > > +++ b/dlibs/aarch64/6.10/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d > > > > > index c2be76d8..7679db2e 100644 > > > > > --- a/dlibs/x86_64/5.11/procfs.d > > > > > +++ b/dlibs/x86_64/5.11/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d > > > > > index c2be76d8..7679db2e 100644 > > > > > --- a/dlibs/x86_64/5.12/procfs.d > > > > > +++ b/dlibs/x86_64/5.12/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d > > > > > index 28fada6d..3a348ebc 100644 > > > > > --- a/dlibs/x86_64/5.14/procfs.d > > > > > +++ b/dlibs/x86_64/5.14/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d > > > > > index cad2d2c5..daf30745 100644 > > > > > --- a/dlibs/x86_64/5.16/procfs.d > > > > > +++ b/dlibs/x86_64/5.16/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d > > > > > index 08696cf7..6ad926ee 100644 > > > > > --- a/dlibs/x86_64/5.2/procfs.d > > > > > +++ b/dlibs/x86_64/5.2/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d > > > > > index c2be76d8..7679db2e 100644 > > > > > --- a/dlibs/x86_64/5.6/procfs.d > > > > > +++ b/dlibs/x86_64/5.6/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d > > > > > index 4cb7b77c..2d52f079 100644 > > > > > --- a/dlibs/x86_64/6.1/procfs.d > > > > > +++ b/dlibs/x86_64/6.1/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d > > > > > index 4cb7b77c..2d52f079 100644 > > > > > --- a/dlibs/x86_64/6.10/procfs.d > > > > > +++ b/dlibs/x86_64/6.10/procfs.d > > > > > @@ -261,6 +261,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; > > > > > diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in > > > > > index e9d50349..827d6b81 100644 > > > > > --- a/libdtrace/procfs.d.in > > > > > +++ b/libdtrace/procfs.d.in > > > > > @@ -307,6 +307,10 @@ inline string root = d_path(&(curthread->fs->root)); > > > > > #pragma D attributes Stable/Stable/Common root > > > > > #pragma D binding "1.0" root > > > > > +inline string execargs = d_execargs(curthread); > > > > > +#pragma D attributes Stable/Stable/Common root > > > > > +#pragma D binding "2.0" execargs > > > > > + > > > > > inline int CLD_EXITED = 1; > > > > > #pragma D binding "1.0" CLD_EXITED > > > > > inline int CLD_KILLED = 2; From alan.maguire at oracle.com Thu Jan 30 11:03:29 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Thu, 30 Jan 2025 11:03:29 +0000 Subject: [DTrace-devel] [PATCH v2 4/6] procfs: implement d_execargs() for pr_psargs translator support In-Reply-To: References: Message-ID: <2187872c-744b-4b1b-bee9-f504ef6376b6@oracle.com> On 29/01/2025 07:00, Kris Van Hees wrote: > Implement d_execargs() to provide task argument string (pr_psargs) > for the psinfo translator. It takes a task (struct task_struct) as > argument and returns a string. > > psinfo->pr_psargs now simply calls d_execargs(T). > thanks for doing this! I was wondering; would there be a case for generalizing the d_execargs() to also capture environment variables (which can be retrieved from the task struct mm struct in a similar null-separated var=value list)? In other words, we pass in the start/end pointers (arg_start, arg_end for task args, env_start, env_end for env var=value strings). Then the function would be a more generic, taking a set of strings between these two start/end addresses and putting them into a single, space-seperated string (d_coalesce_strings() or something might make sense as a name). > Signed-off-by: Kris Van Hees > --- > bpf/Build | 1 + > bpf/d_execargs.S | 91 +++++++++++++++++++ > dlibs/aarch64/5.11/procfs.d | 4 +- > dlibs/aarch64/5.12/procfs.d | 4 +- > dlibs/aarch64/5.14/procfs.d | 4 +- > dlibs/aarch64/5.16/procfs.d | 4 +- > dlibs/aarch64/5.2/procfs.d | 4 +- > dlibs/aarch64/5.6/procfs.d | 4 +- > dlibs/aarch64/6.1/procfs.d | 4 +- > dlibs/aarch64/6.10/procfs.d | 4 +- > dlibs/x86_64/5.11/procfs.d | 4 +- > dlibs/x86_64/5.12/procfs.d | 4 +- > dlibs/x86_64/5.14/procfs.d | 4 +- > dlibs/x86_64/5.16/procfs.d | 4 +- > dlibs/x86_64/5.2/procfs.d | 4 +- > dlibs/x86_64/5.6/procfs.d | 4 +- > dlibs/x86_64/6.1/procfs.d | 4 +- > dlibs/x86_64/6.10/procfs.d | 4 +- > include/dtrace/dif_defines.h | 7 +- > libdtrace/dt_bpf.h | 21 +++-- > libdtrace/dt_cc.c | 33 ++++++- > libdtrace/dt_cg.c | 9 +- > libdtrace/dt_dlibs.c | 3 + > libdtrace/dt_open.c | 2 + > libdtrace/procfs.d.in | 4 +- > .../d_execargs/err.D_PROTO_ARG.scalar_arg.d | 16 ++++ > .../d_execargs/err.D_PROTO_ARG.scalar_arg.r | 4 + > .../d_execargs/err.D_PROTO_ARG.string_arg.d | 16 ++++ > .../d_execargs/err.D_PROTO_ARG.string_arg.r | 4 + > .../d_execargs/err.D_PROTO_ARG.wrong_ptr.d | 16 ++++ > .../d_execargs/err.D_PROTO_ARG.wrong_ptr.r | 4 + > .../d_execargs/err.D_PROTO_LEN.missing_arg.d | 16 ++++ > .../d_execargs/err.D_PROTO_LEN.missing_arg.r | 2 + > .../err.D_PROTO_LEN.too_many_args.d | 16 ++++ > .../err.D_PROTO_LEN.too_many_args.r | 2 + > .../funcs/d_execargs/tst.d_execargs.d | 31 +++++++ > .../funcs/d_execargs/tst.d_execargs.r | 2 + > test/unittest/proc/tst.pr_psargs.d | 31 +++++++ > test/unittest/proc/tst.pr_psargs.r | 9 ++ > 39 files changed, 339 insertions(+), 65 deletions(-) > create mode 100644 bpf/d_execargs.S > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.d > create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.r > create mode 100644 test/unittest/proc/tst.pr_psargs.d > create mode 100644 test/unittest/proc/tst.pr_psargs.r > > diff --git a/bpf/Build b/bpf/Build > index 3e43f4b6..9355326c 100644 > --- a/bpf/Build > +++ b/bpf/Build > @@ -24,6 +24,7 @@ bpf_dlib_SOURCES = \ > agg_lqbin.c agg_qbin.c \ > basename.S \ > cleanpath.S \ > + d_execargs.S \ > dirname.S \ > get_agg.c \ > get_bvar.c \ > diff --git a/bpf/d_execargs.S b/bpf/d_execargs.S > new file mode 100644 > index 00000000..3a5b1270 > --- /dev/null > +++ b/bpf/d_execargs.S > @@ -0,0 +1,91 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2025, Oracle and/or its affiliates. > + */ > + > +#include > +#include > + > + .text > + .align 4 > + .global dt_d_execargs > +dt_d_execargs: > + stxdw [%fp+-8], %r1 /* save dctx to stack */ > + mov %r9, %r3 /* %r9 = args */ > + > + mov %r6, %r2 /* set %r6 in case of error */ > + jeq %r6, 0, .Lerror > + > + add %r6, TASK_MM /* ptr = &(T->mm) */ > + > + mov %r1, %r9 > + mov %r2, 8 > + mov %r3, %r6 > + call BPF_FUNC_probe_read > + jne %r0, 0, .Lerror > + > + ldxdw %r8, [%r9+0] /* %r8 = T->mm */ > + jeq %r8, 0, .Lempty > + mov %r6, %r8 > + add %r6, TASK_MM_ARG_START /* ptr = &(T->mm->arg_start) */ > + > + mov %r1, %r9 > + mov %r2, 8 > + mov %r3, %r6 > + call BPF_FUNC_probe_read > + jne %r0, 0, .Lerror > + > + ldxdw %r7, [%r9+0] /* %r7 = T->mm->arg_start */ > + mov %r6, %r8 > + add %r6, TASK_MM_ARG_END /* ptr = &(T->mm->arg_end) */ > + > + mov %r1, %r9 > + mov %r2, 8 > + mov %r3, %r6 > + call BPF_FUNC_probe_read > + jne %r0, 0, .Lerror > + > + ldxdw %r6, [%r9+0] /* %r6 = T->mm->arg_end */ > + > + mov %r8, %r6 > + sub %r8, %r7 /* %r8 = len = arg_end - arg_start */ > + jslt %r8, 2, .Lempty > + mov %r0, STRSZ > + jslt %r8, %r0, .Llen_ok > + mov %r8, %r0 > +.Llen_ok: > + > + /* read data from arg_start to arg_end */ > + mov %r1, %r9 > + mov %r2, %r8 > + mov %r3, %r7 > + call BPF_FUNC_probe_read /* bpf_probe_read(&args, len + 1, arg_start) */ > + jne %r0, 0, .Lerror > + > + /* loop over args and replace '\0' with ' ' */ > + mov %r1, %r8 > + sub %r1, 2 > +.Lloop: > + mov %r2, %r9 > + add %r2, %r1 > + ldxb %r0, [%r2+0] > + jne %r0, 0, .Lnot_nil > + stb [%r2+0], 32 > +.Lnot_nil: > + sub %r1, 1 > + jsge %r1, 0, .Lloop > + > +.Ldone: > + mov %r0, %r9 > + exit /* return args */ > +.Lerror: > + ldxdw %r1, [%fp+-8] > + mov %r2, PC > + mov %r3, DTRACEFLT_BADADDR > + mov %r4, %r6 > + call dt_probe_error > +.Lempty: > + mov %r0, %r9 > + stb [%r9+0], 0 /* args[0] = 0 */ > + exit /* return args */ > + .size dt_d_execargs, .-dt_d_execargs > diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d > index 44ec4280..70a43ddf 100644 > --- a/dlibs/aarch64/5.11/procfs.d > +++ b/dlibs/aarch64/5.11/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d > index 44ec4280..70a43ddf 100644 > --- a/dlibs/aarch64/5.12/procfs.d > +++ b/dlibs/aarch64/5.12/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d > index 584ac325..ef27bb70 100644 > --- a/dlibs/aarch64/5.14/procfs.d > +++ b/dlibs/aarch64/5.14/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d > index 5aabc6f1..cad2d2c5 100644 > --- a/dlibs/aarch64/5.16/procfs.d > +++ b/dlibs/aarch64/5.16/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d > index 683ff5a8..6b1b1b9c 100644 > --- a/dlibs/aarch64/5.2/procfs.d > +++ b/dlibs/aarch64/5.2/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d > index 44ec4280..70a43ddf 100644 > --- a/dlibs/aarch64/5.6/procfs.d > +++ b/dlibs/aarch64/5.6/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d > index 5d7873b5..4cb7b77c 100644 > --- a/dlibs/aarch64/6.1/procfs.d > +++ b/dlibs/aarch64/6.1/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d > index 5d7873b5..4cb7b77c 100644 > --- a/dlibs/aarch64/6.10/procfs.d > +++ b/dlibs/aarch64/6.10/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d > index 7274554e..c2be76d8 100644 > --- a/dlibs/x86_64/5.11/procfs.d > +++ b/dlibs/x86_64/5.11/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d > index 7274554e..c2be76d8 100644 > --- a/dlibs/x86_64/5.12/procfs.d > +++ b/dlibs/x86_64/5.12/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d > index d1cf90d3..28fada6d 100644 > --- a/dlibs/x86_64/5.14/procfs.d > +++ b/dlibs/x86_64/5.14/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d > index 5aabc6f1..cad2d2c5 100644 > --- a/dlibs/x86_64/5.16/procfs.d > +++ b/dlibs/x86_64/5.16/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d > index 35538862..08696cf7 100644 > --- a/dlibs/x86_64/5.2/procfs.d > +++ b/dlibs/x86_64/5.2/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d > index 7274554e..c2be76d8 100644 > --- a/dlibs/x86_64/5.6/procfs.d > +++ b/dlibs/x86_64/5.6/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d > index 5d7873b5..4cb7b77c 100644 > --- a/dlibs/x86_64/6.1/procfs.d > +++ b/dlibs/x86_64/6.1/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d > index 5d7873b5..4cb7b77c 100644 > --- a/dlibs/x86_64/6.10/procfs.d > +++ b/dlibs/x86_64/6.10/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h > index c8c1d961..cd785723 100644 > --- a/include/dtrace/dif_defines.h > +++ b/include/dtrace/dif_defines.h > @@ -207,10 +207,11 @@ > #define DIF_SUBR_INET_NTOP 41 > #define DIF_SUBR_INET_NTOA 42 > #define DIF_SUBR_INET_NTOA6 43 > -#define DIF_SUBR_D_PATH 44 > -#define DIF_SUBR_LINK_NTOP 45 > +#define DIF_SUBR_LINK_NTOP 44 > +#define DIF_SUBR_D_PATH 45 > +#define DIF_SUBR_D_EXECARGS 46 > > -#define DIF_SUBR_MAX 45 > +#define DIF_SUBR_MAX 46 > > typedef uint32_t dif_instr_t; > > diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h > index 6518de66..85934d2d 100644 > --- a/libdtrace/dt_bpf.h > +++ b/libdtrace/dt_bpf.h > @@ -47,15 +47,18 @@ extern "C" { > #define DT_CONST_TASK_TGID 12 > #define DT_CONST_TASK_REAL_PARENT 13 > #define DT_CONST_TASK_COMM 14 > -#define DT_CONST_MUTEX_OWNER 15 > -#define DT_CONST_RWLOCK_CNTS 16 > -#define DT_CONST_DCTX_RODATA 17 > -#define DT_CONST_RODATA_OFF 18 > -#define DT_CONST_RODATA_SIZE 19 > -#define DT_CONST_ZERO_OFF 20 > -#define DT_CONST_STACK_OFF 21 > -#define DT_CONST_STACK_SKIP 22 > -#define DT_CONST_NPROBES 23 > +#define DT_CONST_TASK_MM 15 > +#define DT_CONST_TASK_MM_ARG_START 16 > +#define DT_CONST_TASK_MM_ARG_END 17 > +#define DT_CONST_MUTEX_OWNER 18 > +#define DT_CONST_RWLOCK_CNTS 19 > +#define DT_CONST_DCTX_RODATA 20 > +#define DT_CONST_RODATA_OFF 21 > +#define DT_CONST_RODATA_SIZE 22 > +#define DT_CONST_ZERO_OFF 23 > +#define DT_CONST_STACK_OFF 24 > +#define DT_CONST_STACK_SKIP 25 > +#define DT_CONST_NPROBES 26 > > #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 29cfbd84..1dc119ea 100644 > --- a/libdtrace/dt_cc.c > +++ b/libdtrace/dt_cc.c > @@ -1082,7 +1082,8 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, > case DT_CONST_TASK_PID: > case DT_CONST_TASK_TGID: > case DT_CONST_TASK_REAL_PARENT: > - case DT_CONST_TASK_COMM: { > + case DT_CONST_TASK_COMM: > + case DT_CONST_TASK_MM: { > ctf_file_t *cfp = dtp->dt_shared_ctf; > ctf_id_t type; > ctf_membinfo_t ctm; > @@ -1108,6 +1109,36 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, > case DT_CONST_TASK_COMM: > rc = ctf_member_info(cfp, type, "comm", &ctm); > break; > + case DT_CONST_TASK_MM: > + rc = ctf_member_info(cfp, type, "mm", &ctm); > + break; > + } > + if (rc == CTF_ERR) > + goto err_ctf; > + nrp->dofr_data = ctm.ctm_offset / NBBY; > + continue; > + } > + case DT_CONST_TASK_MM_ARG_START: > + case DT_CONST_TASK_MM_ARG_END: { > + ctf_file_t *cfp = dtp->dt_shared_ctf; > + ctf_id_t type; > + ctf_membinfo_t ctm; > + int rc = 0; > + > + if (!cfp) > + return dt_set_errno(dtp, EDT_NOCTF); > + > + type = ctf_lookup_by_name(cfp, "struct mm_struct"); > + if (type == CTF_ERR) > + goto err_ctf; > + > + switch (idp->di_id) { > + case DT_CONST_TASK_MM_ARG_START: > + rc = ctf_member_info(cfp, type, "arg_start", &ctm); > + break; > + case DT_CONST_TASK_MM_ARG_END: > + rc = ctf_member_info(cfp, type, "arg_end", &ctm); > + break; > } > if (rc == CTF_ERR) > goto err_ctf; > diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c > index 6e74b4b0..a1a39f3f 100644 > --- a/libdtrace/dt_cg.c > +++ b/libdtrace/dt_cg.c > @@ -3300,7 +3300,6 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > } > > /* built-in variables (note: args[] is handled in dt_cg_array_op) */ > - /* Special case for arg0 through arg9; encode as args[n] */ > if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { > fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); > idx = idp->di_id - DIF_VAR_ARG0; > @@ -6661,6 +6660,13 @@ dt_cg_subr_inet_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > tnp->dn_tstring = NULL; > } > > +static void > +dt_cg_subr_d_execargs(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > +{ > + dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_d_execargs", 0, > + DT_IGNOR, 0, DT_IGNOR, 0); > +} > + > static void > dt_cg_subr_d_path(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > { > @@ -6758,6 +6764,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = { > [DIF_SUBR_INET_NTOP] = &dt_cg_subr_inet_ntop, > [DIF_SUBR_INET_NTOA] = &dt_cg_subr_inet_ntoa, > [DIF_SUBR_INET_NTOA6] = &dt_cg_subr_inet_ntoa6, > + [DIF_SUBR_D_EXECARGS] = &dt_cg_subr_d_execargs, > [DIF_SUBR_D_PATH] = &dt_cg_subr_d_path, > [DIF_SUBR_LINK_NTOP] = &dt_cg_subr_link_ntop, > }; > diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c > index 07d22afd..9ad4f5e7 100644 > --- a/libdtrace/dt_dlibs.c > +++ b/libdtrace/dt_dlibs.c > @@ -89,6 +89,9 @@ static const dt_ident_t dt_bpf_symbols[] = { > DT_BPF_SYMBOL_ID(TASK_TGID, DT_IDENT_SCALAR, DT_CONST_TASK_TGID), > DT_BPF_SYMBOL_ID(TASK_REAL_PARENT, DT_IDENT_SCALAR, DT_CONST_TASK_REAL_PARENT), > DT_BPF_SYMBOL_ID(TASK_COMM, DT_IDENT_SCALAR, DT_CONST_TASK_COMM), > + DT_BPF_SYMBOL_ID(TASK_MM, DT_IDENT_SCALAR, DT_CONST_TASK_MM), > + DT_BPF_SYMBOL_ID(TASK_MM_ARG_START, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_START), > + DT_BPF_SYMBOL_ID(TASK_MM_ARG_END, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_END), > DT_BPF_SYMBOL_ID(MUTEX_OWNER, DT_IDENT_SCALAR, DT_CONST_MUTEX_OWNER), > DT_BPF_SYMBOL_ID(RWLOCK_CNTS, DT_IDENT_SCALAR, DT_CONST_RWLOCK_CNTS), > DT_BPF_SYMBOL_ID(DCTX_RODATA, DT_IDENT_SCALAR, DT_CONST_DCTX_RODATA), > diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c > index a0205887..c8208de6 100644 > --- a/libdtrace/dt_open.c > +++ b/libdtrace/dt_open.c > @@ -138,6 +138,8 @@ static const dt_ident_t _dtrace_globals[] = { > { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE, > DTRACE_CLASS_COMMON }, DT_VERS_1_0, > &dt_idops_type, "vmlinux`struct task_struct *" }, > +{ "d_execargs", DT_IDENT_FUNC, 0, DIF_SUBR_D_EXECARGS, DT_ATTR_EVOLCMN, > + DT_VERS_2_0, &dt_idops_func, "string(vmlinux`struct task_struct *)" }, > { "d_path", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_D_PATH, DT_ATTR_EVOLCMN, > DT_VERS_1_0, &dt_idops_func, "string(struct path *)" }, > { "ddi_pathname", DT_IDENT_FUNC, 0, DIF_SUBR_DDI_PATHNAME, > diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in > index 038cf69b..e9d50349 100644 > --- a/libdtrace/procfs.d.in > +++ b/libdtrace/procfs.d.in > @@ -179,9 +179,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > new file mode 100644 > index 00000000..c707184d > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > @@ -0,0 +1,16 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: The argument to d_execargs() should be a (struct task_struct *). > + */ > + > +BEGIN > +{ > + trace(d_execargs(1)); > + exit(0); > +} > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > new file mode 100644 > index 00000000..0e9cda07 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > @@ -0,0 +1,4 @@ > +-- @@stderr -- > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > + prototype: struct task_struct * > + argument: int > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > new file mode 100644 > index 00000000..ba419689 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > @@ -0,0 +1,16 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: The argument to d_execargs() should be (struct task_struct *). > + */ > + > +BEGIN > +{ > + trace(d_execargs("a")); > + exit(0); > +} > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > new file mode 100644 > index 00000000..ac1c1401 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > @@ -0,0 +1,4 @@ > +-- @@stderr -- > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > + prototype: struct task_struct * > + argument: string > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > new file mode 100644 > index 00000000..473e35e4 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > @@ -0,0 +1,16 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: The argument to d_execargs() should be (struct task_struct *). > + */ > + > +BEGIN > +{ > + trace(d_execargs(curthread->mm)); > + exit(0); > +} > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > new file mode 100644 > index 00000000..842371a3 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > @@ -0,0 +1,4 @@ > +-- @@stderr -- > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > + prototype: struct task_struct * > + argument: struct mm_struct * > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > new file mode 100644 > index 00000000..86b1b237 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > @@ -0,0 +1,16 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: d_execargs() requires an argument > + */ > + > +BEGIN > +{ > + trace(d_execargs()); > + exit(0); > +} > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > new file mode 100644 > index 00000000..a4fcd162 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > @@ -0,0 +1,2 @@ > +-- @@stderr -- > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 0 args passed, 1 expected > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > new file mode 100644 > index 00000000..3add63f6 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > @@ -0,0 +1,16 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: The d_execargs() subroutine accepts no more than one argument. > + */ > + > +BEGIN > +{ > + trace(d_execargs(curthread, 1)); > + exit(0); > +} > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > new file mode 100644 > index 00000000..f5a982ff > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > @@ -0,0 +1,2 @@ > +-- @@stderr -- > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 2 args passed, 1 expected > diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.d b/test/unittest/funcs/d_execargs/tst.d_execargs.d > new file mode 100644 > index 00000000..b8b141aa > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/tst.d_execargs.d > @@ -0,0 +1,31 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: d_execargs() provides correct results. > + */ > + > +#pragma D option destructive > +#pragma D option quiet > + > +BEGIN > +{ > + mypid = pid; > + system("/bin/echo TEST"); > +} > + > +proc:::exec-success > +/progenyof(mypid) && d_execargs(curthread) == "/bin/echo TEST"/ > +{ > + trace(d_execargs(curthread)); > + exit(0); > +} > + > +tick-1s > +{ > + exit(1); > +} > diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.r b/test/unittest/funcs/d_execargs/tst.d_execargs.r > new file mode 100644 > index 00000000..d8ff6689 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/tst.d_execargs.r > @@ -0,0 +1,2 @@ > +TEST > +/bin/echo TEST > diff --git a/test/unittest/proc/tst.pr_psargs.d b/test/unittest/proc/tst.pr_psargs.d > new file mode 100644 > index 00000000..902ac1a3 > --- /dev/null > +++ b/test/unittest/proc/tst.pr_psargs.d > @@ -0,0 +1,31 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: psinfo->pr_psargs provides correct results. > + */ > + > +#pragma D option destructive > +#pragma D option quiet > + > +BEGIN > +{ > + mypid = pid; > + system("/bin/echo TEST"); > +} > + > +proc:::exec-success > +/progenyof(mypid) && curpsinfo->pr_psargs == "/bin/echo TEST"/ > +{ > + trace(curpsinfo->pr_psargs); > + exit(0); > +} > + > +tick-1s > +{ > + exit(1); > +} > diff --git a/test/unittest/proc/tst.pr_psargs.r b/test/unittest/proc/tst.pr_psargs.r > new file mode 100644 > index 00000000..397c8717 > --- /dev/null > +++ b/test/unittest/proc/tst.pr_psargs.r > @@ -0,0 +1,9 @@ > +TEST > + > + 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef > + 0: 2f 62 69 6e 2f 65 63 68 6f 20 54 45 53 54 00 00 /bin/echo TEST.. > + 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > + 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > + 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > + 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > + From alan.maguire at oracle.com Thu Jan 30 11:12:56 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Thu, 30 Jan 2025 11:12:56 +0000 Subject: [DTrace-devel] [PATCH v2 0/4] ELF note-based USDT support In-Reply-To: References: <20250129145522.512341-1-alan.maguire@oracle.com> Message-ID: <407bef64-903d-43a0-a5e9-071eef13c27d@oracle.com> On 29/01/2025 15:33, Kris Van Hees wrote: > Thank you for rebasing your work on the newest tree. That will certainly > help review them and move things forward. > > I would definitely rework the commit message though, because > > 1. DTrace has a specific understanding of what USDT probes are and how they > work and stap-based probes do not provide the same functionality. One > example of that you already point ay: they are not discoverable - i.e. > they are not registered upon startup which is why you need to refer to > them directly by provider name (with embedded pid). I think you need to > be very clear about the distinction. Using STAPSDT or stapsdt might be > a better choice than referring to USDT. > sure; I'll use stapsdt. > 2. I think that the commit message fails to highlight that this support is > to make it possible to trace programs (and shared librearies)that have been > built with stap style probes. I don't think it is in the best interest of > DTrace users to build their executables and shared libraries with stap > style probes over DTrace USDT probes, especially given the significant > advantage that DTrace USDT probes have (see 1. above). > > 3. While I can see the point of mentioning how to add stapsdt probes to > code, it also is a source for confusion and thus is probably better left > out. Since this is a compability feature, surely those wanting to use it > already have executables with such probes or know how to create them. > By including it here, you also introduce the very unfortunate fact that > stapsdt uses DTRACE_PROBE*() macros even though the probes have never really > been DTrace compatible, and it is only with your proposed patch now that > they could be used in DTrace. The systemtap project shouldn't have > piggy-backed on DTRACE_PROBE*() in the first place because it causes this > type of confusion and complications, so I would very much prefer not to > highlight that mess with this patch series. > > The stap probe support is very significant because we unfortunately do have to > live with a world where there are multiple ways that such userspace probes > have been implemented. And given that packages are released with probes and > people may want to trace them makes this addition certainly very worthwhile. > But I think it should be clear that this is for compatibilty/interoperability > purposes only. > Sounds good, I'll rework the patches accordingly. Alan > Kris > > On Wed, Jan 29, 2025 at 02:55:18PM +0000, Alan Maguire wrote: >> This series adds support (patch 1) for ELF-note defined USDT >> probes in binaries and libraries; patches 2-4 add tests. >> >> Basic pid-specific USDT support is added; i.e. it is necessary >> to specify the target pid in the provider name such as >> "example1234" ; future work could add pid wildcarding. >> >> ELF note defined probes are defined by including sys/sdt.h >> from the systemtap-sdt-devel package, and are defined in >> C programs via >> >> DTRACE_PROBEn(provider, probe, [args...]) >> >> See the tests for concrete examples. >> >> For python, go, etc, USDT probes can be added via libstapsdt [1] >> and associated language-specific bindings. This allows users >> of those languages to add USDT probes too. For example, the >> following example program adds a "pythonapp" probe "firstProbe" >> using the python-specific libstapsdt binding: >> >> #!/usr/bin/python3 >> from time import sleep >> import stapsdt >> provider = stapsdt.Provider("pythonapp") >> probe = provider.add_probe( >> "firstProbe", stapsdt.ArgTypes.uint64, stapsdt.ArgTypes.int32) >> provider.load() >> while True: >> print("Firing probe...") >> if probe.fire("My little probe", 42): >> print("Probe fired!") >> sleep(1) >> >> We can then trace this via dtrace: >> >> # dtrace -n 'pythonapp503211:::* { printf("args %s, %d\n", copyinstr(arg0), arg1); }' >> >> dtrace: description 'pythonapp503211:::* ' matched 1 probe >> CPU ID FUNCTION:NAME >> 6 286628 :firstProbe args My little probe, 42 >> >> [1] https://github.com/linux-usdt/libstapsdt >> >> Alan Maguire (4): >> USDT: support ELF-note-defined probes >> selftests/usdt: add test for USDT note-defined probe firing, args >> selftests/usdt: add test for USDT notes in shared library >> selftests/usdt: add test covering different forms of USDT note args >> >> include/dtrace/pid.h | 29 ++ >> libdtrace/dt_cg.c | 47 ++ >> libdtrace/dt_cg.h | 1 + >> libdtrace/dt_pid.c | 466 ++++++++++++++++++++ >> libdtrace/dt_prov_uprobe.c | 19 +- >> test/unittest/usdt/sdt_notes.h | 504 ++++++++++++++++++++++ >> test/unittest/usdt/tst.usdt-notes-args.r | 2 + >> test/unittest/usdt/tst.usdt-notes-args.sh | 51 +++ >> test/unittest/usdt/tst.usdt-notes-lib.r | 14 + >> test/unittest/usdt/tst.usdt-notes-lib.sh | 145 +++++++ >> test/unittest/usdt/tst.usdt-notes.r | 14 + >> test/unittest/usdt/tst.usdt-notes.sh | 121 ++++++ >> 12 files changed, 1406 insertions(+), 7 deletions(-) >> create mode 100644 test/unittest/usdt/sdt_notes.h >> create mode 100644 test/unittest/usdt/tst.usdt-notes-args.r >> create mode 100755 test/unittest/usdt/tst.usdt-notes-args.sh >> create mode 100644 test/unittest/usdt/tst.usdt-notes-lib.r >> create mode 100755 test/unittest/usdt/tst.usdt-notes-lib.sh >> create mode 100644 test/unittest/usdt/tst.usdt-notes.r >> create mode 100755 test/unittest/usdt/tst.usdt-notes.sh >> >> -- >> 2.43.5 >> From alan.maguire at oracle.com Thu Jan 30 14:43:03 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Thu, 30 Jan 2025 14:43:03 +0000 Subject: [DTrace-devel] [PATCH v3 0/4] add support for stapsdt probes Message-ID: <20250130144307.1297654-1-alan.maguire@oracle.com> As well as using dtrace -G to generate USDT probes, programs and libraries may have added static probes via stapsdt ELF notes. This series adds support for such probes. Patch 1 adds the support, while patches 2-4 add tests covering that support. Changes since v2: - updated terminology to distinguish stapsdt from USDT probes Alan Maguire (4): support stapsdt ELF-note-defined static probes selftests/usdt: add test for stapsdt note-defined probe firing, args selftests/usdt: add test for stapsdt notes in shared library selftests/usdt: add test covering different forms of stapsdt note args include/dtrace/pid.h | 29 ++ libdtrace/dt_cg.c | 47 ++ libdtrace/dt_cg.h | 1 + libdtrace/dt_pid.c | 467 +++++++++++++++++ libdtrace/dt_prov_uprobe.c | 19 +- test/unittest/usdt/sdt_notes.h | 504 +++++++++++++++++++ test/unittest/usdt/tst.stapsdt-notes-args.r | 2 + test/unittest/usdt/tst.stapsdt-notes-args.sh | 50 ++ test/unittest/usdt/tst.stapsdt-notes-lib.r | 14 + test/unittest/usdt/tst.stapsdt-notes-lib.sh | 145 ++++++ test/unittest/usdt/tst.stapsdt-notes.r | 14 + test/unittest/usdt/tst.stapsdt-notes.sh | 121 +++++ 12 files changed, 1406 insertions(+), 7 deletions(-) create mode 100644 test/unittest/usdt/sdt_notes.h create mode 100644 test/unittest/usdt/tst.stapsdt-notes-args.r create mode 100755 test/unittest/usdt/tst.stapsdt-notes-args.sh create mode 100644 test/unittest/usdt/tst.stapsdt-notes-lib.r create mode 100755 test/unittest/usdt/tst.stapsdt-notes-lib.sh create mode 100644 test/unittest/usdt/tst.stapsdt-notes.r create mode 100755 test/unittest/usdt/tst.stapsdt-notes.sh -- 2.43.5 From alan.maguire at oracle.com Thu Jan 30 14:43:04 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Thu, 30 Jan 2025 14:43:04 +0000 Subject: [DTrace-devel] [PATCH v3 1/4] support stapsdt ELF-note-defined static probes In-Reply-To: <20250130144307.1297654-1-alan.maguire@oracle.com> References: <20250130144307.1297654-1-alan.maguire@oracle.com> Message-ID: <20250130144307.1297654-2-alan.maguire@oracle.com> As well as using dtrace -G to generate USDT probes, programs and libraries may have added static probes via stapsdt ELF notes. Read ELF notes from /proc//exe and associated libraries, and parse them to retrieve uprobe address and argument-related info to create the associated uprobe. The painful part here is retrieving info from the string of stapsdt arguments in the ELF note such that we can generate trampoline code to retrieve the probe arguments. Probe arguments can be either constants, register values or dereferences from register values (plus offset). Use bpf_probe_read[_user] for the latter case. Translating from the register names in the argument string is platform-specific, so we use arrays mapping the register names used to the appropriate pt_regs field name, along with an offset (for the aarch64 case where the regs[] array in user_pt_regs is used). Wildcarded pid stapsdt probes are not yet supported; a specific pid is required. As well as supporting ELF-note stapsdt defined probes in programs and libraries, this patch supports dynamically-created probes that are created via libstapsdt [1]. libstapsdt allows dynamic languages like python to declare and fire probes by dynamically creating a memfd-based shared library containing ELF notes for the probes. With these changes we can also trace these probes. This is very useful since libstapsdt has python, NodeJS, go and luaJIT bindings. [1] https://github.com/linux-usdt/libstapsdt Signed-off-by: Alan Maguire --- include/dtrace/pid.h | 29 +++ libdtrace/dt_cg.c | 47 ++++ libdtrace/dt_cg.h | 1 + libdtrace/dt_pid.c | 467 +++++++++++++++++++++++++++++++++++++ libdtrace/dt_prov_uprobe.c | 19 +- 5 files changed, 556 insertions(+), 7 deletions(-) diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h index c53e6004..2723c6af 100644 --- a/include/dtrace/pid.h +++ b/include/dtrace/pid.h @@ -26,6 +26,27 @@ typedef enum pid_probetype { DTPPT_IS_ENABLED } pid_probetype_t; +#define DT_STAPSDT_MAX_ARGS 10 + +enum dt_stapsdt_arg_type { + DT_STAPSDT_ARG_NONE = 0, + DT_STAPSDT_ARG_CONST, + DT_STAPSDT_ARG_REG, + DT_STAPSDT_ARG_REG_DEREF +}; + +struct dt_stapsdt_arg { + enum dt_stapsdt_arg_type sa_type; + int sa_val_sz; + int sa_val_off; + int64_t sa_const_val; + const char *sa_regs_name; /* pt_regs/user_pt_regs */ + const char *sa_regs_field; /* x0/rsp etc */ + int sa_regs_field_off; /* used for array regs[] */ +}; + +typedef struct dt_stapsdt_arg dt_stapsdt_arg_t; + typedef struct pid_probespec { pid_probetype_t pps_type; /* probe type */ char *pps_prv; /* provider (without pid) */ @@ -44,6 +65,14 @@ typedef struct pid_probespec { size_t pps_xargvlen; /* (high estimate of) length of array */ int8_t *pps_argmap; /* mapped arg indexes */ + int pps_nsargs; /* number of arg specs in + * pps_sargs + */ + dt_stapsdt_arg_t pps_sargs[DT_STAPSDT_MAX_ARGS]; + /* USDT ELF note-defined + * provider arguments. + */ + /* * Fields below this point do not apply to underlying probes. */ diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index e7e3a132..93c1ec12 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -651,6 +651,53 @@ dt_cg_tramp_copy_rval_from_regs(dt_pcb_t *pcb) emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), 0)); } +void +dt_cg_tramp_copy_args_from_stapsdt_spec(dt_pcb_t *pcb, const dt_stapsdt_arg_t *args) +{ + dtrace_hdl_t *dtp = pcb->pcb_hdl; + dt_irlist_t *dlp = &pcb->pcb_ir; + int reg_val_off, i; + + for (i = 0; i < DT_STAPSDT_MAX_ARGS; i++) { + const dt_stapsdt_arg_t *arg = &args[i]; + uint_t lbl_ok = dt_irlist_label(dlp); + + switch (arg->sa_type) { + case DT_STAPSDT_ARG_NONE: + return; + case DT_STAPSDT_ARG_CONST: + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), + arg->sa_const_val)); + break; + case DT_STAPSDT_ARG_REG: + case DT_STAPSDT_ARG_REG_DEREF: + reg_val_off = dt_cg_ctf_offsetof(arg->sa_regs_name, + arg->sa_regs_field, NULL, 0); + reg_val_off += arg->sa_regs_field_off; + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, + reg_val_off)); + /* do direct register value copy */ + if (arg->sa_type == DT_STAPSDT_ARG_REG) { + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), + BPF_REG_0)); + break; + } + /* otherwise call bpf_probe_read[_user] to get dereferenced value. + */ + emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_7)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DMST_ARG(i))); + emit(dlp, BPF_MOV_IMM(BPF_REG_2, abs(arg->sa_val_sz))); + emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, arg->sa_val_off)); + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user])); + emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_ok)); + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), 0)); + emitl(dlp, lbl_ok, BPF_NOP()); + break; + } + } +} + static dt_node_t * dt_cg_tramp_var(const char *name) { diff --git a/libdtrace/dt_cg.h b/libdtrace/dt_cg.h index fb26c125..c6c5c95b 100644 --- a/libdtrace/dt_cg.h +++ b/libdtrace/dt_cg.h @@ -28,6 +28,7 @@ extern void dt_cg_tramp_copy_regs(dt_pcb_t *pcb); extern void dt_cg_tramp_copy_args_from_regs(dt_pcb_t *pcb, int called); extern void dt_cg_tramp_copy_pc_from_regs(dt_pcb_t *pcb); extern void dt_cg_tramp_copy_rval_from_regs(dt_pcb_t *pcb); +extern void dt_cg_tramp_copy_args_from_stapsdt_spec(dt_pcb_t *pcb, const dt_stapsdt_arg_t *args); extern void dt_cg_tramp_decl_var(dt_pcb_t *pcb, dt_ident_t *idp); extern void dt_cg_tramp_get_var(dt_pcb_t *pcb, const char *name, int isstore, int reg); diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index 4d53c023..f1d76159 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -28,6 +28,8 @@ #if defined(__amd64) #include #endif +#include +#include #include #include @@ -780,6 +782,369 @@ validate_dof_record(const char *path, const dof_parsed_t *parsed, return 1; } +#define SEC_STAPSDT_NOTE ".note.stapsdt" +#define NAME_STAPSDT_NOTE "stapsdt" + +struct pt_regs_info { + const char sa_name[8]; + const char name[8]; + int off; +} pt_regs_info[] = { + +#if defined(__aarch64__) + { "sp", "sp", 0 }, + { "x0", "regs", 0 }, + { "x1", "regs", 1 * sizeof(unsigned long) }, + { "x2", "regs", 2 * sizeof(unsigned long) }, + { "x3", "regs", 3 * sizeof(unsigned long) }, + { "x4", "regs", 4 * sizeof(unsigned long) }, + { "x5", "regs", 5 * sizeof(unsigned long) }, + { "x6", "regs", 6 * sizeof(unsigned long) }, + { "x7", "regs", 7 * sizeof(unsigned long) }, + { "x8", "regs", 8 * sizeof(unsigned long) }, + { "x9", "regs", 9 * sizeof(unsigned long) }, + { "x10", "regs", 10 * sizeof(unsigned long) }, + { "x11", "regs", 11 * sizeof(unsigned long) }, + { "x12", "regs", 12 * sizeof(unsigned long) }, + { "x13", "regs", 13 * sizeof(unsigned long) }, + { "x14", "regs", 14 * sizeof(unsigned long) }, + { "x15", "regs", 15 * sizeof(unsigned long) }, + { "x16", "regs", 16 * sizeof(unsigned long) }, + { "x17", "regs", 17 * sizeof(unsigned long) }, + { "x18", "regs", 18 * sizeof(unsigned long) }, + { "x19", "regs", 19 * sizeof(unsigned long) }, + { "x20", "regs", 20 * sizeof(unsigned long) }, + { "x21", "regs", 21 * sizeof(unsigned long) }, + { "x222", "regs", 22 * sizeof(unsigned long) }, + { "x23", "regs", 23 * sizeof(unsigned long) }, + { "x24", "regs", 24 * sizeof(unsigned long) }, + { "x25", "regs", 25 * sizeof(unsigned long) }, + { "x26", "regs", 26 * sizeof(unsigned long) }, + { "x27", "regs", 27 * sizeof(unsigned long) }, + { "x28", "regs", 28 * sizeof(unsigned long) }, + { "x29", "regs", 29 * sizeof(unsigned long) }, + { "x30", "regs", 30 * sizeof(unsigned long) }, + { "x31", "regs", 31 * sizeof(unsigned long) } +#else + { "rip", "ip", 0 }, + { "eip", "ip", 0 }, + { "rax", "ax", 0 }, + { "eax", "ax", 0 }, + { "ax", "ax", 0 }, + { "al", "ax", 0 }, + { "rbx", "bx", 0 }, + { "ebx", "bx", 0 }, + { "bx", "bx", 0 }, + { "bl", "bx", 0 }, + { "rcx", "cx", 0 }, + { "ecx", "cx", 0 }, + { "cx", "cx", 0 }, + { "cl", "cx", 0 }, + { "rdx", "dx", 0 }, + { "edx", "dx", 0 }, + { "dx", "dx", 0 }, + { "dl", "dx", 0 }, + { "rsi", "si", 0 }, + { "esi", "si", 0 }, + { "si", "si", 0 }, + { "sil", "si", 0 }, + { "rdi", "di", 0 }, + { "edi", "di", 0 }, + { "di", "di", 0 }, + { "dil", "di", 0 }, + { "rbp", "bp", 0 }, + { "ebp", "bp", 0 }, + { "bp", "bp", 0 }, + { "bpl", "bp", 0 }, + { "rsp", "sp", 0 }, + { "esp", "sp", 0 }, + { "sp", "sp", 0 }, + { "spl", "sp", 0 } +#endif +}; + +static void dt_stapsdt_print_arg(dt_stapsdt_arg_t *a) +{ + switch (a->sa_type) { + case DT_STAPSDT_ARG_NONE: + return; + case DT_STAPSDT_ARG_CONST: + dt_dprintf("CONST %ld\n", a->sa_const_val); + break; + case DT_STAPSDT_ARG_REG_DEREF: + dt_dprintf("REG DEREF (%s.%s + %d) + %d\n", + a->sa_regs_name, a->sa_regs_field, + a->sa_regs_field_off, a->sa_val_off); + break; + case DT_STAPSDT_ARG_REG: + dt_dprintf("REG VALUE (%s.%s + %d)\n", + a->sa_regs_name, a->sa_regs_field, + a->sa_regs_field_off); + break; + } +} + +/* retrieve arguments; space-separated string of arguments of form: + * [-]numbytes@[optional_offset_from(]%regname[)] + * + * for example: + * + * -4 at -4(%rbp) means memory dereference of 4 bytes, 4 bytes + * offset from %rbp value. + * 8@(%rax) means memory dereference of 8 bytes from + * rax register value (no offset) + * 8@%rax means 8 bytes from rax register value (no deref). + * 4@$32 means 4 byte constant value 32 + */ +static int dt_stapsdt_parse_arg(char **argstr, struct dt_stapsdt_arg *a) +{ + char *arg = *argstr; + char reg[8] = {}; + int len; + + if (sscanf(arg, +#if defined(__aarch64__) + " %d @ \[ %[a-z0-9] , %d ] %n", + &a->sa_val_sz, reg, &a->sa_val_off, &len) +#else + " %d @ %d ( %%%8[^)] ) %n", + &a->sa_val_sz, &a->sa_val_off, reg, &len) +#endif + == 3) { + a->sa_type = DT_STAPSDT_ARG_REG_DEREF; + } else if (sscanf(arg, +#if defined(__aarch64__) + " %d @ \[ %7[a-z0-9] ] %n", &a->sa_val_sz, reg, &len) +#else + " %d @ ( %%%7[^)] ) %n", &a->sa_val_sz, reg, &len) +#endif + == 2) { + a->sa_type = DT_STAPSDT_ARG_REG_DEREF; + } else if (sscanf(arg, +#if defined(__x86_64__) + " %d @ $%ld %n", &a->sa_val_sz, &a->sa_const_val, &len) +#else + " %d @ %ld %n", &a->sa_val_sz, &a->sa_const_val, &len) +#endif + == 2) { + a->sa_type = DT_STAPSDT_ARG_CONST; + } else if (sscanf(arg, +#if defined(__aarch64__) + " %d @ %7[a-z0-9] %n", &a->sa_val_sz, reg, &len) +#else + " %d @ %%%7s %n", &a->sa_val_sz, reg, &len) +#endif + == 2) { + a->sa_type = DT_STAPSDT_ARG_REG; + } else { + return -1; + } + if (strlen(reg) > 0) { + int i; + +#if defined(__aarch64__) + a->sa_regs_name = "struct user_pt_regs"; +#else + a->sa_regs_name = "struct pt_regs"; +#endif + for (i = 0; i < ARRAY_SIZE(pt_regs_info); i++) { + if (strcmp(pt_regs_info[i].sa_name, reg)) + continue; + a->sa_regs_field = pt_regs_info[i].name; + a->sa_regs_field_off = pt_regs_info[i].off; + } + } + *argstr += len; + return 0; +} + +static int dt_stapsdt_parse(dtrace_hdl_t *dtp, dt_proc_t *dpr, + dtrace_probedesc_t *pdp, dt_pcb_t *pcb, + const dt_provider_t *pvp, char *path, + unsigned long base_addr) +{ + Elf *elf; + Elf_Scn *scn = NULL; + GElf_Shdr shdr; + GElf_Nhdr nhdr; + size_t shstrndx, noff, doff, off, n; + Elf_Data *data; + GElf_Ehdr ehdr; + int i, ret = 0; + int fd = -1; + char *mod; + + dt_dprintf("Scanning for USDT probes in ELF notes in '%s' (pid %i) matching %s:%s:%s\n", + path, dpr->dpr_pid, pdp->mod, pdp->fun, pdp->prb); + + fd = open(path, O_RDONLY); + if (fd < 0) { + dt_pid_error(dtp, pcb, dpr, D_PROC_USDT, + "Cannot open %s: %s\n", + path, strerror(errno)); + return -1; + } + mod = strrchr(path, '/'); + if (mod) + mod++; + else + mod = path; + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); // ELF_C_READ ? + assert(elf_kind(elf) == ELF_K_ELF); + elf_getshdrstrndx(elf, &shstrndx); + + if (gelf_getehdr(elf, &ehdr)) { + switch (ehdr.e_type) { + case ET_EXEC: + /* binary does not require base addr adjustment */ + base_addr = 0; + break; + case ET_DYN: + break; + default: + dt_dprintf("unexpected ELF hdr type 0x%x for '%s'\n", + ehdr.e_type, path); + ret = -1; + goto out; + } + } + + while (1) { + char *secname; + + scn = elf_nextscn(elf, scn); + if (scn == NULL) { + /* no ELF notes found, not an error */ + goto out; + } + assert(gelf_getshdr(scn, &shdr) != NULL); + + secname = elf_strptr(elf, shstrndx, shdr.sh_name); + if (strcmp(secname, SEC_STAPSDT_NOTE) == 0 && + shdr.sh_type == SHT_NOTE) + break; + } + /* No ELF notes, just bail. */ + if (scn == NULL) + goto out; + data = elf_getdata(scn, 0); + for (off = 0; + (off = gelf_getnote(data, off, &nhdr, &noff, &doff)) > 0;) { + pid_probespec_t psp = {0}; + char *prv, *prb; + const char *fun; + char *dbuf = (char *)data->d_buf; + long *addrs = data->d_buf + doff; /* 3 addrs are loc/base/semaphore */ + GElf_Sym sym; + const prmap_t *pmp; + int nargs = 0; + + if (strncmp(dbuf + noff, NAME_STAPSDT_NOTE, nhdr.n_namesz) != 0) + continue; + prv = dbuf + doff + (3*sizeof(long)); + /* ensure prv/prb is null-terminated */ + assert(strlen(prv) < nhdr.n_descsz); + prb = prv + strlen(prv) + 1; + assert(strlen(prb) < nhdr.n_descsz); + if (strncmp(pdp->prv, prv, strlen(prv)) != 0) + continue; + if (strcmp(pdp->prb, "*") != 0 && strcmp(pdp->prb, prb) != 0) + continue; + /* retrieve arguments; space-separated string of arguments + * in form: + * [-]numbytes@[optional_offset_from(]%regname[)] + * + * for example: + * + * -4 at -4(%rbp) means memory dereference of 4 bytes, 4 bytes + * offset from %rbp value. + * 8@(%rax) means memory dereference of 8 bytes from + * rax register value (no offset) + * 8@%rax means 8 bytes from rax register value (no deref). + * 4@$32 means 4 byte constant value 32 + */ + if (prb + strlen(prb) + 1 < dbuf + doff + nhdr.n_descsz) { + char *argstr = prb + strlen(prb) + 1; + + while (dt_stapsdt_parse_arg(&argstr, + &psp.pps_sargs[nargs]) == 0 && + nargs < DT_STAPSDT_MAX_ARGS) { + dt_stapsdt_print_arg(&psp.pps_sargs[nargs]); + nargs++; + } + psp.pps_nsargs = nargs; + + } + dt_dprintf("found ELF note for provider '%s', probe '%s' in %s, loc 0x%lx, base 0x%lx, nargs %d\n", + prv, prb, path, addrs[0], addrs[1], nargs); + psp.pps_type = DTPPT_USDT; + psp.pps_prv = prv; + psp.pps_mod = mod; + psp.pps_prb = prb; + if (elf_getphdrnum(elf, &n)) + continue; + for (i = 0; i < n; i++) { + GElf_Phdr phdr; + + if (!gelf_getphdr(elf, i, &phdr)) + break; + + if (addrs[0] < phdr.p_vaddr || + addrs[0] > phdr.p_vaddr + phdr.p_memsz) + continue; + if (base_addr) + psp.pps_off = addrs[0]; + else + psp.pps_off = addrs[0] - phdr.p_vaddr + phdr.p_offset; + break; + } + if (!psp.pps_off) + continue; + psp.pps_nameoff = 0; + + pmp = Paddr_to_map(dpr->dpr_proc, base_addr + addrs[0]); + if (!pmp) { + dt_dprintf("%i: cannot determine 0x%lx's mapping\n", + Pgetpid(dpr->dpr_proc), psp.pps_off); + continue; + } + psp.pps_fn = Pmap_mapfile_name(dpr->dpr_proc, pmp); + if (psp.pps_fn == NULL) { + dt_pid_error(dtp, pcb, dpr, D_PROC_USDT, + "Cannot get name of mapping containing probe %s for pid %d\n", + psp.pps_prb, dpr->dpr_pid); + ret = -1; + break; + } + if (dt_Plookup_by_addr(dtp, dpr->dpr_pid, base_addr + addrs[0], + &fun, &sym) == 0) + psp.pps_fun = (char *)fun; + else + psp.pps_fun = ""; + psp.pps_dev = pmp->pr_dev; + psp.pps_inum = pmp->pr_inum; + psp.pps_pid = dpr->dpr_pid; + psp.pps_nameoff = 0; + + dt_dprintf("providing %s:%s:%s:%s for pid %d at addr 0x%lx\n", psp.pps_prv, + psp.pps_mod, psp.pps_fun, psp.pps_prb, psp.pps_pid, + base_addr + addrs[0]); + if (pvp->impl->provide_probe(dtp, &psp) < 0) { + dt_pid_error(dtp, pcb, dpr, D_PROC_USDT, + "failed to instantiate probe %s for pid %d: %s", + psp.pps_prb, psp.pps_pid, + dtrace_errmsg(dtp, dtrace_errno(dtp))); + ret = -1; + } + free(psp.pps_fn); + if (ret == -1) + break; + } +out: + elf_end(elf); + close(fd); + return ret; +} /* * Create underlying probes relating to the probespec passed on input. @@ -1202,6 +1567,106 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *p return err; } +static int +dt_pid_create_stapsdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, + dt_pcb_t *pcb) +{ + const char *pidstr = &pdp->prv[strlen(pdp->prv)]; + const dt_provider_t *pvp; + char path[PATH_MAX + 1]; + dt_proc_t *dpr = NULL; + char line[1024]; + FILE *fp = NULL; + pid_t pid = 0; + int err = 0; + + /* only specific pids are support for ELF notes for now... */ + while (isdigit(*(pidstr - 1))) + pidstr--; + if (strlen(pidstr) > 0) + pid = atoll(pidstr); + if (!Pexists(pid)) + return 0; + pvp = dt_provider_lookup(dtp, "usdt"); + assert(pvp != NULL); + + if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING | + DTRACE_PROC_SHORTLIVED) < 0) { + dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, + "failed to grab process %d", + (int)pid); + return 1; + } + dpr = dt_proc_lookup(dtp, pid); + assert(dpr != NULL); + + snprintf(path, sizeof(path), "/proc/%d/maps", pid); + fp = fopen(path, "r"); + if (!fp) { + dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, + "no /proc/%d/maps found", (int)pid); + err = 1; + goto out; + } + while (fgets(line, sizeof(line) - 1, fp) != NULL) { + long addr_start, addr_end, file_offset; + long dev_major, dev_minor; + unsigned long inode; + char name[PATH_MAX + 1]; + char perm[5]; + int ret; + + ret = sscanf(line, + "%lx-%lx %4s %lx %lx:%lx %lu %[^\n]", + &addr_start, &addr_end, perm, &file_offset, + &dev_major, &dev_minor, &inode, name); + if (ret != 8 || !strchr(perm, 'x') || strchr(name, '[') != NULL) + continue; + + /* libstapsdt uses an memfd-based library to dynamically create + * stapsdt notes for dynamic languages like python; we need + * the associated /proc//fds/ fd to read these notes. + */ + if (strncmp(name, "/memfd:", strlen("/memfd:")) == 0) { + DIR *d; + struct dirent *dirent; + char *deleted; + + deleted = strstr(name, " (deleted)"); + *deleted = '\0'; + snprintf(path, sizeof(path), "/proc/%d/fd", pid); + d = opendir(path); + if (d == NULL) + continue; + while ((dirent = readdir(d)) != NULL) { + struct stat s; + + snprintf(path, sizeof(path), "/proc/%d/fd/%s", + pid, dirent->d_name); + if (stat(path, &s) != 0 || s.st_ino != inode) + continue; + if (dt_stapsdt_parse(dtp, dpr, pdp, pcb, pvp, + path, addr_start) != 0) { + err = 1; + goto out; + } + } + } else { + if (dt_stapsdt_parse(dtp, dpr, pdp, pcb, pvp, name, + addr_start) != 0) { + err = 1; + goto out; + } + } + } +out: + if (fp) + fclose(fp); + dt_pid_fix_mod(NULL, pdp, dtp, dpr->dpr_pid); + dt_proc_release_unlock(dtp, pid); + return err; +} + int dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb) { @@ -1273,6 +1738,8 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t * free(globpat); globfree(&globbuf); + err = dt_pid_create_stapsdt_probes(pdp, dtp, pcb); + /* If no errors, report success. */ if (err == 0) return 0; diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index 78d9aed6..24dca53e 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -51,6 +51,7 @@ static const char prvname[] = "uprobe"; #define PP_IS_ENABLED 0x4 #define PP_IS_USDT 0x8 #define PP_IS_MAPPED 0x10 +#define PP_IS_STAPSDT_NOTE 0x20 typedef struct dt_uprobe { dev_t dev; @@ -58,6 +59,7 @@ typedef struct dt_uprobe { char *fn; uint64_t off; int flags; + dt_stapsdt_arg_t sargs[DT_STAPSDT_MAX_ARGS]; tp_probe_t *tp; int argc; /* number of args */ dt_argdesc_t *args; /* args array (points into argvbuf) */ @@ -651,7 +653,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, pd.prb = prb; dt_dprintf("Providing underlying probe %s:%s:%s:%s @ %lx\n", psp->pps_prv, - psp->pps_mod, psp->pps_fn, psp->pps_prb, psp->pps_off); + psp->pps_mod, psp->pps_fun, psp->pps_prb, psp->pps_off); uprp = dt_probe_lookup(dtp, &pd); if (uprp == NULL) { dt_provider_t *pvp; @@ -671,6 +673,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, upp->off = psp->pps_off; upp->fn = strdup(psp->pps_fn); upp->tp = dt_tp_alloc(dtp); + memcpy(&upp->sargs, psp->pps_sargs, sizeof(upp->sargs)); if (upp->tp == NULL) goto fail; @@ -702,11 +705,11 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, break; case DTPPT_USDT: upp->flags |= PP_IS_USDT; + if (psp->pps_nsargs) + upp->flags |= PP_IS_STAPSDT_NOTE; + break; + default: break; - default: ; - /* - * No flags needed for other types. - */ } return uprp; @@ -973,8 +976,10 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) /* 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); + else if (upp->flags & PP_IS_STAPSDT_NOTE) + dt_cg_tramp_copy_args_from_stapsdt_spec(pcb, upp->sargs); + else + dt_cg_tramp_copy_args_from_regs(pcb, 0); /* * Apply arg mappings, if needed. -- 2.43.5 From alan.maguire at oracle.com Thu Jan 30 14:43:05 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Thu, 30 Jan 2025 14:43:05 +0000 Subject: [DTrace-devel] [PATCH v3 2/4] selftests/usdt: add test for stapsdt note-defined probe firing, args In-Reply-To: <20250130144307.1297654-1-alan.maguire@oracle.com> References: <20250130144307.1297654-1-alan.maguire@oracle.com> Message-ID: <20250130144307.1297654-3-alan.maguire@oracle.com> Add test identical to the args tests to verify probe firing and arg retrieval work for stapsdt notes-defined STAP_PROBEn() probes. Need a copy of the sdt.h file which is public domain, so add it in the test directory. Signed-off-by: Alan Maguire --- test/unittest/usdt/sdt_notes.h | 504 ++++++++++++++++++++++++ test/unittest/usdt/tst.stapsdt-notes.r | 14 + test/unittest/usdt/tst.stapsdt-notes.sh | 121 ++++++ 3 files changed, 639 insertions(+) create mode 100644 test/unittest/usdt/sdt_notes.h create mode 100644 test/unittest/usdt/tst.stapsdt-notes.r create mode 100755 test/unittest/usdt/tst.stapsdt-notes.sh diff --git a/test/unittest/usdt/sdt_notes.h b/test/unittest/usdt/sdt_notes.h new file mode 100644 index 00000000..ec5423e2 --- /dev/null +++ b/test/unittest/usdt/sdt_notes.h @@ -0,0 +1,504 @@ +/* - Systemtap static probe definition macros. + + This file is dedicated to the public domain, pursuant to CC0 + (https://creativecommons.org/publicdomain/zero/1.0/) +*/ + +#ifndef _SYS_SDT_H +#define _SYS_SDT_H 1 + +/* + This file defines a family of macros + + STAP_PROBEn(op1, ..., opn) + + that emit a nop into the instruction stream, and some data into an auxiliary + note section. The data in the note section describes the operands, in terms + of size and location. Each location is encoded as assembler operand string. + Consumer tools such as gdb or systemtap insert breakpoints on top of + the nop, and decode the location operand-strings, like an assembler, + to find the values being passed. + + The operand strings are selected by the compiler for each operand. + They are constrained by gcc inline-assembler codes. The default is: + + #define STAP_SDT_ARG_CONSTRAINT nor + + This is a good default if the operands tend to be integral and + moderate in number (smaller than number of registers). In other + cases, the compiler may report "'asm' requires impossible reload" or + similar. In this case, consider simplifying the macro call (fewer + and simpler operands), reduce optimization, or override the default + constraints string via: + + #define STAP_SDT_ARG_CONSTRAINT g + #include + + See also: + https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation + https://gcc.gnu.org/onlinedocs/gcc/Constraints.html + */ + + + +#ifdef __ASSEMBLER__ +# define _SDT_PROBE(provider, name, n, arglist) \ + _SDT_ASM_BODY(provider, name, _SDT_ASM_SUBSTR_1, (_SDT_DEPAREN_##n arglist)) \ + _SDT_ASM_BASE +# define _SDT_ASM_1(x) x; +# define _SDT_ASM_2(a, b) a,b; +# define _SDT_ASM_3(a, b, c) a,b,c; +# define _SDT_ASM_5(a, b, c, d, e) a,b,c,d,e; +# define _SDT_ASM_STRING_1(x) .asciz #x; +# define _SDT_ASM_SUBSTR_1(x) .ascii #x; +# define _SDT_DEPAREN_0() /* empty */ +# define _SDT_DEPAREN_1(a) a +# define _SDT_DEPAREN_2(a,b) a b +# define _SDT_DEPAREN_3(a,b,c) a b c +# define _SDT_DEPAREN_4(a,b,c,d) a b c d +# define _SDT_DEPAREN_5(a,b,c,d,e) a b c d e +# define _SDT_DEPAREN_6(a,b,c,d,e,f) a b c d e f +# define _SDT_DEPAREN_7(a,b,c,d,e,f,g) a b c d e f g +# define _SDT_DEPAREN_8(a,b,c,d,e,f,g,h) a b c d e f g h +# define _SDT_DEPAREN_9(a,b,c,d,e,f,g,h,i) a b c d e f g h i +# define _SDT_DEPAREN_10(a,b,c,d,e,f,g,h,i,j) a b c d e f g h i j +# define _SDT_DEPAREN_11(a,b,c,d,e,f,g,h,i,j,k) a b c d e f g h i j k +# define _SDT_DEPAREN_12(a,b,c,d,e,f,g,h,i,j,k,l) a b c d e f g h i j k l +#else +#if defined _SDT_HAS_SEMAPHORES +#define _SDT_NOTE_SEMAPHORE_USE(provider, name) \ + __asm__ __volatile__ ("" :: "m" (provider##_##name##_semaphore)); +#else +#define _SDT_NOTE_SEMAPHORE_USE(provider, name) +#endif + +# define _SDT_PROBE(provider, name, n, arglist) \ + do { \ + _SDT_NOTE_SEMAPHORE_USE(provider, name); \ + __asm__ __volatile__ (_SDT_ASM_BODY(provider, name, _SDT_ASM_ARGS, (n)) \ + :: _SDT_ASM_OPERANDS_##n arglist); \ + __asm__ __volatile__ (_SDT_ASM_BASE); \ + } while (0) +# define _SDT_S(x) #x +# define _SDT_ASM_1(x) _SDT_S(x) "\n" +# define _SDT_ASM_2(a, b) _SDT_S(a) "," _SDT_S(b) "\n" +# define _SDT_ASM_3(a, b, c) _SDT_S(a) "," _SDT_S(b) "," \ + _SDT_S(c) "\n" +# define _SDT_ASM_5(a, b, c, d, e) _SDT_S(a) "," _SDT_S(b) "," \ + _SDT_S(c) "," _SDT_S(d) "," \ + _SDT_S(e) "\n" +# define _SDT_ASM_ARGS(n) _SDT_ASM_TEMPLATE_##n +# define _SDT_ASM_STRING_1(x) _SDT_ASM_1(.asciz #x) +# define _SDT_ASM_SUBSTR_1(x) _SDT_ASM_1(.ascii #x) + +# define _SDT_ARGFMT(no) _SDT_ASM_1(_SDT_SIGN %n[_SDT_S##no]) \ + _SDT_ASM_1(_SDT_SIZE %n[_SDT_S##no]) \ + _SDT_ASM_1(_SDT_TYPE %n[_SDT_S##no]) \ + _SDT_ASM_SUBSTR(_SDT_ARGTMPL(_SDT_A##no)) + + +# ifndef STAP_SDT_ARG_CONSTRAINT +# if defined __powerpc__ +# define STAP_SDT_ARG_CONSTRAINT nZr +# elif defined __arm__ +# define STAP_SDT_ARG_CONSTRAINT g +# else +# define STAP_SDT_ARG_CONSTRAINT nor +# endif +# endif + +# define _SDT_STRINGIFY(x) #x +# define _SDT_ARG_CONSTRAINT_STRING(x) _SDT_STRINGIFY(x) +/* _SDT_S encodes the size and type as 0xSSTT which is decoded by the assembler + macros _SDT_SIZE and _SDT_TYPE */ +# define _SDT_ARG(n, x) \ + [_SDT_S##n] "n" ((_SDT_ARGSIGNED (x) ? (int)-1 : 1) * (-(((int) _SDT_ARGSIZE (x)) << 8) + (-(0x7f & __builtin_classify_type (x))))), \ + [_SDT_A##n] _SDT_ARG_CONSTRAINT_STRING (STAP_SDT_ARG_CONSTRAINT) (_SDT_ARGVAL (x)) +#endif +#define _SDT_ASM_STRING(x) _SDT_ASM_STRING_1(x) +#define _SDT_ASM_SUBSTR(x) _SDT_ASM_SUBSTR_1(x) + +#define _SDT_ARGARRAY(x) (__builtin_classify_type (x) == 14 \ + || __builtin_classify_type (x) == 5) + +#ifdef __cplusplus +# define _SDT_ARGSIGNED(x) (!_SDT_ARGARRAY (x) \ + && __sdt_type<__typeof (x)>::__sdt_signed) +# define _SDT_ARGSIZE(x) (_SDT_ARGARRAY (x) \ + ? sizeof (void *) : sizeof (x)) +# define _SDT_ARGVAL(x) (x) + +# include + +template +struct __sdt_type +{ + static const bool __sdt_signed = false; +}; + +#define __SDT_ALWAYS_SIGNED(T) \ +template<> struct __sdt_type { static const bool __sdt_signed = true; }; +#define __SDT_COND_SIGNED(T,CT) \ +template<> struct __sdt_type { static const bool __sdt_signed = ((CT)(-1) < 1); }; +__SDT_ALWAYS_SIGNED(signed char) +__SDT_ALWAYS_SIGNED(short) +__SDT_ALWAYS_SIGNED(int) +__SDT_ALWAYS_SIGNED(long) +__SDT_ALWAYS_SIGNED(long long) +__SDT_ALWAYS_SIGNED(volatile signed char) +__SDT_ALWAYS_SIGNED(volatile short) +__SDT_ALWAYS_SIGNED(volatile int) +__SDT_ALWAYS_SIGNED(volatile long) +__SDT_ALWAYS_SIGNED(volatile long long) +__SDT_ALWAYS_SIGNED(const signed char) +__SDT_ALWAYS_SIGNED(const short) +__SDT_ALWAYS_SIGNED(const int) +__SDT_ALWAYS_SIGNED(const long) +__SDT_ALWAYS_SIGNED(const long long) +__SDT_ALWAYS_SIGNED(const volatile signed char) +__SDT_ALWAYS_SIGNED(const volatile short) +__SDT_ALWAYS_SIGNED(const volatile int) +__SDT_ALWAYS_SIGNED(const volatile long) +__SDT_ALWAYS_SIGNED(const volatile long long) +__SDT_COND_SIGNED(char, char) +__SDT_COND_SIGNED(wchar_t, wchar_t) +__SDT_COND_SIGNED(volatile char, char) +__SDT_COND_SIGNED(volatile wchar_t, wchar_t) +__SDT_COND_SIGNED(const char, char) +__SDT_COND_SIGNED(const wchar_t, wchar_t) +__SDT_COND_SIGNED(const volatile char, char) +__SDT_COND_SIGNED(const volatile wchar_t, wchar_t) +#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) +/* __SDT_COND_SIGNED(char16_t) */ +/* __SDT_COND_SIGNED(char32_t) */ +#endif + +template +struct __sdt_type<__sdt_E[]> : public __sdt_type<__sdt_E *> {}; + +template +struct __sdt_type<__sdt_E[__sdt_N]> : public __sdt_type<__sdt_E *> {}; + +#elif !defined(__ASSEMBLER__) +__extension__ extern unsigned long long __sdt_unsp; +# define _SDT_ARGINTTYPE(x) \ + __typeof (__builtin_choose_expr (((__builtin_classify_type (x) \ + + 3) & -4) == 4, (x), 0U)) +# define _SDT_ARGSIGNED(x) \ + (!__extension__ \ + (__builtin_constant_p ((((unsigned long long) \ + (_SDT_ARGINTTYPE (x)) __sdt_unsp) \ + & ((unsigned long long)1 << (sizeof (unsigned long long) \ + * __CHAR_BIT__ - 1))) == 0) \ + || (_SDT_ARGINTTYPE (x)) -1 > (_SDT_ARGINTTYPE (x)) 0)) +# define _SDT_ARGSIZE(x) \ + (_SDT_ARGARRAY (x) ? sizeof (void *) : sizeof (x)) +# define _SDT_ARGVAL(x) (x) +#endif + +#if defined __powerpc__ || defined __powerpc64__ +# define _SDT_ARGTMPL(id) %I[id]%[id] +#elif defined __i386__ +# define _SDT_ARGTMPL(id) %k[id] /* gcc.gnu.org/PR80115 sourceware.org/PR24541 */ +#else +# define _SDT_ARGTMPL(id) %[id] +#endif + +/* NB: gdb PR24541 highlighted an unspecified corner of the sdt.h + operand note format. + + The named register may be a longer or shorter (!) alias for the + storage where the value in question is found. For example, on + i386, 64-bit value may be put in register pairs, and the register + name stored would identify just one of them. Previously, gcc was + asked to emit the %w[id] (16-bit alias of some registers holding + operands), even when a wider 32-bit value was used. + + Bottom line: the byte-width given before the @ sign governs. If + there is a mismatch between that width and that of the named + register, then a sys/sdt.h note consumer may need to employ + architecture-specific heuristics to figure out where the compiler + has actually put the complete value. +*/ + +#ifdef __LP64__ +# define _SDT_ASM_ADDR .8byte +#else +# define _SDT_ASM_ADDR .4byte +#endif + +/* The ia64 and s390 nop instructions take an argument. */ +#if defined(__ia64__) || defined(__s390__) || defined(__s390x__) +#define _SDT_NOP nop 0 +#else +#define _SDT_NOP nop +#endif + +#define _SDT_NOTE_NAME "stapsdt" +#define _SDT_NOTE_TYPE 3 + +# define _SDT_ASM_AUTOGROUP "?" + +#define _SDT_DEF_MACROS \ + _SDT_ASM_1(.altmacro) \ + _SDT_ASM_1(.macro _SDT_SIGN x) \ + _SDT_ASM_3(.pushsection .note.stapsdt,"","note") \ + _SDT_ASM_1(.iflt \\x) \ + _SDT_ASM_1(.ascii "-") \ + _SDT_ASM_1(.endif) \ + _SDT_ASM_1(.popsection) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_SIZE_ x) \ + _SDT_ASM_3(.pushsection .note.stapsdt,"","note") \ + _SDT_ASM_1(.ascii "\x") \ + _SDT_ASM_1(.popsection) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_SIZE x) \ + _SDT_ASM_1(_SDT_SIZE_ %%((-(-\\x*((-\\x>0)-(-\\x<0))))>>8)) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_TYPE_ x) \ + _SDT_ASM_3(.pushsection .note.stapsdt,"","note") \ + _SDT_ASM_2(.ifc 8,\\x) \ + _SDT_ASM_1(.ascii "f") \ + _SDT_ASM_1(.endif) \ + _SDT_ASM_1(.ascii "@") \ + _SDT_ASM_1(.popsection) \ + _SDT_ASM_1(.endm) \ + _SDT_ASM_1(.macro _SDT_TYPE x) \ + _SDT_ASM_1(_SDT_TYPE_ %%((\\x)&(0xff))) \ + _SDT_ASM_1(.endm) + +#define _SDT_UNDEF_MACROS \ + _SDT_ASM_1(.purgem _SDT_SIGN) \ + _SDT_ASM_1(.purgem _SDT_SIZE_) \ + _SDT_ASM_1(.purgem _SDT_SIZE) \ + _SDT_ASM_1(.purgem _SDT_TYPE_) \ + _SDT_ASM_1(.purgem _SDT_TYPE) + +#define _SDT_ASM_BODY(provider, name, pack_args, args, ...) \ + _SDT_DEF_MACROS \ + _SDT_ASM_1(990: _SDT_NOP) \ + _SDT_ASM_3( .pushsection .note.stapsdt,_SDT_ASM_AUTOGROUP,"note") \ + _SDT_ASM_1( .balign 4) \ + _SDT_ASM_3( .4byte 992f-991f, 994f-993f, _SDT_NOTE_TYPE) \ + _SDT_ASM_1(991: .asciz _SDT_NOTE_NAME) \ + _SDT_ASM_1(992: .balign 4) \ + _SDT_ASM_1(993: _SDT_ASM_ADDR 990b) \ + _SDT_ASM_1( _SDT_ASM_ADDR _.stapsdt.base) \ + _SDT_SEMAPHORE(provider,name) \ + _SDT_ASM_STRING(provider) \ + _SDT_ASM_STRING(name) \ + pack_args args \ + _SDT_ASM_SUBSTR(\x00) \ + _SDT_UNDEF_MACROS \ + _SDT_ASM_1(994: .balign 4) \ + _SDT_ASM_1( .popsection) + +#define _SDT_ASM_BASE \ + _SDT_ASM_1(.ifndef _.stapsdt.base) \ + _SDT_ASM_5( .pushsection .stapsdt.base,"aG","progbits", \ + .stapsdt.base,comdat) \ + _SDT_ASM_1( .weak _.stapsdt.base) \ + _SDT_ASM_1( .hidden _.stapsdt.base) \ + _SDT_ASM_1( _.stapsdt.base: .space 1) \ + _SDT_ASM_2( .size _.stapsdt.base, 1) \ + _SDT_ASM_1( .popsection) \ + _SDT_ASM_1(.endif) + +#if defined _SDT_HAS_SEMAPHORES +#define _SDT_SEMAPHORE(p,n) \ + _SDT_ASM_1( _SDT_ASM_ADDR p##_##n##_semaphore) +#else +#define _SDT_SEMAPHORE(p,n) _SDT_ASM_1( _SDT_ASM_ADDR 0) +#endif + +#define _SDT_ASM_BLANK _SDT_ASM_SUBSTR(\x20) +#define _SDT_ASM_TEMPLATE_0 /* no arguments */ +#define _SDT_ASM_TEMPLATE_1 _SDT_ARGFMT(1) +#define _SDT_ASM_TEMPLATE_2 _SDT_ASM_TEMPLATE_1 _SDT_ASM_BLANK _SDT_ARGFMT(2) +#define _SDT_ASM_TEMPLATE_3 _SDT_ASM_TEMPLATE_2 _SDT_ASM_BLANK _SDT_ARGFMT(3) +#define _SDT_ASM_TEMPLATE_4 _SDT_ASM_TEMPLATE_3 _SDT_ASM_BLANK _SDT_ARGFMT(4) +#define _SDT_ASM_TEMPLATE_5 _SDT_ASM_TEMPLATE_4 _SDT_ASM_BLANK _SDT_ARGFMT(5) +#define _SDT_ASM_TEMPLATE_6 _SDT_ASM_TEMPLATE_5 _SDT_ASM_BLANK _SDT_ARGFMT(6) +#define _SDT_ASM_TEMPLATE_7 _SDT_ASM_TEMPLATE_6 _SDT_ASM_BLANK _SDT_ARGFMT(7) +#define _SDT_ASM_TEMPLATE_8 _SDT_ASM_TEMPLATE_7 _SDT_ASM_BLANK _SDT_ARGFMT(8) +#define _SDT_ASM_TEMPLATE_9 _SDT_ASM_TEMPLATE_8 _SDT_ASM_BLANK _SDT_ARGFMT(9) +#define _SDT_ASM_TEMPLATE_10 _SDT_ASM_TEMPLATE_9 _SDT_ASM_BLANK _SDT_ARGFMT(10) +#define _SDT_ASM_TEMPLATE_11 _SDT_ASM_TEMPLATE_10 _SDT_ASM_BLANK _SDT_ARGFMT(11) +#define _SDT_ASM_TEMPLATE_12 _SDT_ASM_TEMPLATE_11 _SDT_ASM_BLANK _SDT_ARGFMT(12) +#define _SDT_ASM_OPERANDS_0() [__sdt_dummy] "g" (0) +#define _SDT_ASM_OPERANDS_1(arg1) _SDT_ARG(1, arg1) +#define _SDT_ASM_OPERANDS_2(arg1, arg2) \ + _SDT_ASM_OPERANDS_1(arg1), _SDT_ARG(2, arg2) +#define _SDT_ASM_OPERANDS_3(arg1, arg2, arg3) \ + _SDT_ASM_OPERANDS_2(arg1, arg2), _SDT_ARG(3, arg3) +#define _SDT_ASM_OPERANDS_4(arg1, arg2, arg3, arg4) \ + _SDT_ASM_OPERANDS_3(arg1, arg2, arg3), _SDT_ARG(4, arg4) +#define _SDT_ASM_OPERANDS_5(arg1, arg2, arg3, arg4, arg5) \ + _SDT_ASM_OPERANDS_4(arg1, arg2, arg3, arg4), _SDT_ARG(5, arg5) +#define _SDT_ASM_OPERANDS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ + _SDT_ASM_OPERANDS_5(arg1, arg2, arg3, arg4, arg5), _SDT_ARG(6, arg6) +#define _SDT_ASM_OPERANDS_7(arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + _SDT_ASM_OPERANDS_6(arg1, arg2, arg3, arg4, arg5, arg6), _SDT_ARG(7, arg7) +#define _SDT_ASM_OPERANDS_8(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ + _SDT_ASM_OPERANDS_7(arg1, arg2, arg3, arg4, arg5, arg6, arg7), \ + _SDT_ARG(8, arg8) +#define _SDT_ASM_OPERANDS_9(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9) \ + _SDT_ASM_OPERANDS_8(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8), \ + _SDT_ARG(9, arg9) +#define _SDT_ASM_OPERANDS_10(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) \ + _SDT_ASM_OPERANDS_9(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9), \ + _SDT_ARG(10, arg10) +#define _SDT_ASM_OPERANDS_11(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11) \ + _SDT_ASM_OPERANDS_10(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10), \ + _SDT_ARG(11, arg11) +#define _SDT_ASM_OPERANDS_12(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12) \ + _SDT_ASM_OPERANDS_11(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11), \ + _SDT_ARG(12, arg12) + +/* These macros can be used in C, C++, or assembly code. + In assembly code the arguments should use normal assembly operand syntax. */ + +#define STAP_PROBE(provider, name) \ + _SDT_PROBE(provider, name, 0, ()) +#define STAP_PROBE1(provider, name, arg1) \ + _SDT_PROBE(provider, name, 1, (arg1)) +#define STAP_PROBE2(provider, name, arg1, arg2) \ + _SDT_PROBE(provider, name, 2, (arg1, arg2)) +#define STAP_PROBE3(provider, name, arg1, arg2, arg3) \ + _SDT_PROBE(provider, name, 3, (arg1, arg2, arg3)) +#define STAP_PROBE4(provider, name, arg1, arg2, arg3, arg4) \ + _SDT_PROBE(provider, name, 4, (arg1, arg2, arg3, arg4)) +#define STAP_PROBE5(provider, name, arg1, arg2, arg3, arg4, arg5) \ + _SDT_PROBE(provider, name, 5, (arg1, arg2, arg3, arg4, arg5)) +#define STAP_PROBE6(provider, name, arg1, arg2, arg3, arg4, arg5, arg6) \ + _SDT_PROBE(provider, name, 6, (arg1, arg2, arg3, arg4, arg5, arg6)) +#define STAP_PROBE7(provider, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ + _SDT_PROBE(provider, name, 7, (arg1, arg2, arg3, arg4, arg5, arg6, arg7)) +#define STAP_PROBE8(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) \ + _SDT_PROBE(provider, name, 8, (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)) +#define STAP_PROBE9(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)\ + _SDT_PROBE(provider, name, 9, (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)) +#define STAP_PROBE10(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10) \ + _SDT_PROBE(provider, name, 10, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)) +#define STAP_PROBE11(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11) \ + _SDT_PROBE(provider, name, 11, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)) +#define STAP_PROBE12(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12) \ + _SDT_PROBE(provider, name, 12, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)) + +/* This STAP_PROBEV macro can be used in variadic scenarios, where the + number of probe arguments is not known until compile time. Since + variadic macro support may vary with compiler options, you must + pre-#define SDT_USE_VARIADIC to enable this type of probe. + + The trick to count __VA_ARGS__ was inspired by this post by + Laurent Deniau : + http://groups.google.com/group/comp.std.c/msg/346fc464319b1ee5 + + Note that our _SDT_NARG is called with an extra 0 arg that's not + counted, so we don't have to worry about the behavior of macros + called without any arguments. */ + +#define _SDT_NARG(...) __SDT_NARG(__VA_ARGS__, 12,11,10,9,8,7,6,5,4,3,2,1,0) +#define __SDT_NARG(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12, N, ...) N +#ifdef SDT_USE_VARIADIC +#define _SDT_PROBE_N(provider, name, N, ...) \ + _SDT_PROBE(provider, name, N, (__VA_ARGS__)) +#define STAP_PROBEV(provider, name, ...) \ + _SDT_PROBE_N(provider, name, _SDT_NARG(0, ##__VA_ARGS__), ##__VA_ARGS__) +#endif + +/* These macros are for use in asm statements. You must compile + with -std=gnu99 or -std=c99 to use the STAP_PROBE_ASM macro. + + The STAP_PROBE_ASM macro generates a quoted string to be used in the + template portion of the asm statement, concatenated with strings that + contain the actual assembly code around the probe site. + + For example: + + asm ("before\n" + STAP_PROBE_ASM(provider, fooprobe, %eax 4(%esi)) + "after"); + + emits the assembly code for "before\nafter", with a probe in between. + The probe arguments are the %eax register, and the value of the memory + word located 4 bytes past the address in the %esi register. Note that + because this is a simple asm, not a GNU C extended asm statement, these + % characters do not need to be doubled to generate literal %reg names. + + In a GNU C extended asm statement, the probe arguments can be specified + using the macro STAP_PROBE_ASM_TEMPLATE(n) for n arguments. The paired + macro STAP_PROBE_ASM_OPERANDS gives the C values of these probe arguments, + and appears in the input operand list of the asm statement. For example: + + asm ("someinsn %0,%1\n" // %0 is output operand, %1 is input operand + STAP_PROBE_ASM(provider, fooprobe, STAP_PROBE_ASM_TEMPLATE(3)) + "otherinsn %[namedarg]" + : "r" (outvar) + : "g" (some_value), [namedarg] "i" (1234), + STAP_PROBE_ASM_OPERANDS(3, some_value, some_ptr->field, 1234)); + + This is just like writing: + + STAP_PROBE3(provider, fooprobe, some_value, some_ptr->field, 1234)); + + but the probe site is right between "someinsn" and "otherinsn". + + The probe arguments in STAP_PROBE_ASM can be given as assembly + operands instead, even inside a GNU C extended asm statement. + Note that these can use operand templates like %0 or %[name], + and likewise they must write %%reg for a literal operand of %reg. */ + +#define _SDT_ASM_BODY_1(p,n,...) _SDT_ASM_BODY(p,n,_SDT_ASM_SUBSTR,(__VA_ARGS__)) +#define _SDT_ASM_BODY_2(p,n,...) _SDT_ASM_BODY(p,n,/*_SDT_ASM_STRING */,__VA_ARGS__) +#define _SDT_ASM_BODY_N2(p,n,no,...) _SDT_ASM_BODY_ ## no(p,n,__VA_ARGS__) +#define _SDT_ASM_BODY_N1(p,n,no,...) _SDT_ASM_BODY_N2(p,n,no,__VA_ARGS__) +#define _SDT_ASM_BODY_N(p,n,...) _SDT_ASM_BODY_N1(p,n,_SDT_NARG(0, __VA_ARGS__),__VA_ARGS__) + +#if __STDC_VERSION__ >= 199901L +# define STAP_PROBE_ASM(provider, name, ...) \ + _SDT_ASM_BODY_N(provider, name, __VA_ARGS__) \ + _SDT_ASM_BASE +# define STAP_PROBE_ASM_OPERANDS(n, ...) _SDT_ASM_OPERANDS_##n(__VA_ARGS__) +#else +# define STAP_PROBE_ASM(provider, name, args) \ + _SDT_ASM_BODY(provider, name, /* _SDT_ASM_STRING */, (args)) \ + _SDT_ASM_BASE +#endif +#define STAP_PROBE_ASM_TEMPLATE(n) _SDT_ASM_TEMPLATE_##n,"use _SDT_ASM_TEMPLATE_" + + +/* DTrace compatible macro names. */ +#define DTRACE_PROBE(provider,probe) \ + STAP_PROBE(provider,probe) +#define DTRACE_PROBE1(provider,probe,parm1) \ + STAP_PROBE1(provider,probe,parm1) +#define DTRACE_PROBE2(provider,probe,parm1,parm2) \ + STAP_PROBE2(provider,probe,parm1,parm2) +#define DTRACE_PROBE3(provider,probe,parm1,parm2,parm3) \ + STAP_PROBE3(provider,probe,parm1,parm2,parm3) +#define DTRACE_PROBE4(provider,probe,parm1,parm2,parm3,parm4) \ + STAP_PROBE4(provider,probe,parm1,parm2,parm3,parm4) +#define DTRACE_PROBE5(provider,probe,parm1,parm2,parm3,parm4,parm5) \ + STAP_PROBE5(provider,probe,parm1,parm2,parm3,parm4,parm5) +#define DTRACE_PROBE6(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6) \ + STAP_PROBE6(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6) +#define DTRACE_PROBE7(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7) \ + STAP_PROBE7(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7) +#define DTRACE_PROBE8(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) \ + STAP_PROBE8(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8) +#define DTRACE_PROBE9(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) \ + STAP_PROBE9(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9) +#define DTRACE_PROBE10(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) \ + STAP_PROBE10(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10) +#define DTRACE_PROBE11(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11) \ + STAP_PROBE11(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11) +#define DTRACE_PROBE12(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11,parm12) \ + STAP_PROBE12(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11,parm12) + + +#endif /* sys/sdt.h */ diff --git a/test/unittest/usdt/tst.stapsdt-notes.r b/test/unittest/usdt/tst.stapsdt-notes.r new file mode 100644 index 00000000..db6d18cb --- /dev/null +++ b/test/unittest/usdt/tst.stapsdt-notes.r @@ -0,0 +1,14 @@ +test:main:zero +test:main:one:1 +test:main:two:2:3 +test:main:three:4:5:7 +test:main:four:7:8:9:10 +test:main:five:11:12:13:14:15 +test:main:six:16:17:18:19:20:21 +test:main:seven:22:23:24:25:26:27:28 +test:main:eight:29:30:31:32:33:34:35:36 +test:main:nine:37:38:39:40:41:42:43:44:45 +test:main:ten:46:47:48:49:50:51:52:53:54:55 +test:main:eleven:56:57:58:59:60:61:62:63:64:65 +test:main:twelve:67:68:69:70:71:72:73:74:75:76 + diff --git a/test/unittest/usdt/tst.stapsdt-notes.sh b/test/unittest/usdt/tst.stapsdt-notes.sh new file mode 100755 index 00000000..1d132a59 --- /dev/null +++ b/test/unittest/usdt/tst.stapsdt-notes.sh @@ -0,0 +1,121 @@ +#!/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 covers all stapsdt probes fired by the STAP_PROBEn macros. +# Arguments values are checked only for first 10 arguments because +# there is support for arg0 ... arg9 only at this moment. + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="-I${PWD}/test/unittest/usdt" + +DIRNAME="$tmpdir/usdt-notes.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > test.c < + +int +main(int argc, char **argv) +{ + STAP_PROBE(test_prov, zero); + STAP_PROBE1(test_prov, one, argc); + STAP_PROBE2(test_prov, two, 2, 3); + STAP_PROBE3(test_prov, three, 4, 5, 7); + STAP_PROBE4(test_prov, four, 7, 8, 9, 10); + STAP_PROBE5(test_prov, five, 11, 12, 13, 14, 15); + STAP_PROBE6(test_prov, six, 16, 17, 18, 19, 20, 21); + STAP_PROBE7(test_prov, seven, 22, 23, 24, 25, 26, 27, 28); + STAP_PROBE8(test_prov, eight, 29, 30, 31, 32, 33, 34, 35, 36); + STAP_PROBE9(test_prov, nine, 37, 38, 39, 40, 41, 42, 43, 44, 45); + STAP_PROBE10(test_prov, ten, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55); + STAP_PROBE11(test_prov, eleven, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66); + STAP_PROBE12(test_prov, twelve, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78); +} +EOF + +${CC} ${CFLAGS} -o test test.c +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi + +$dtrace -c ./test -qs /dev/stdin < References: <20250130144307.1297654-1-alan.maguire@oracle.com> Message-ID: <20250130144307.1297654-4-alan.maguire@oracle.com> To ensure stapsdt notes are found/fire for shared libraries, create a shared library and trace the stapsdt probes in it. To ensure the library is loaded when DTrace has started, call it early in the program lifetime and sleep until DTrace starts; at that point trace the probes with the pid and ensure they fire with expected args. Signed-off-by: Alan Maguire --- test/unittest/usdt/tst.stapsdt-notes-lib.r | 14 ++ test/unittest/usdt/tst.stapsdt-notes-lib.sh | 145 ++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 test/unittest/usdt/tst.stapsdt-notes-lib.r create mode 100755 test/unittest/usdt/tst.stapsdt-notes-lib.sh diff --git a/test/unittest/usdt/tst.stapsdt-notes-lib.r b/test/unittest/usdt/tst.stapsdt-notes-lib.r new file mode 100644 index 00000000..7c667a4d --- /dev/null +++ b/test/unittest/usdt/tst.stapsdt-notes-lib.r @@ -0,0 +1,14 @@ +libstapsdttest.so:libfn:zero +libstapsdttest.so:libfn:one:1 +libstapsdttest.so:libfn:two:2:3 +libstapsdttest.so:libfn:three:4:5:7 +libstapsdttest.so:libfn:four:7:8:9:10 +libstapsdttest.so:libfn:five:11:12:13:14:15 +libstapsdttest.so:libfn:six:16:17:18:19:20:21 +libstapsdttest.so:libfn:seven:22:23:24:25:26:27:28 +libstapsdttest.so:libfn:eight:29:30:31:32:33:34:35:36 +libstapsdttest.so:libfn:nine:37:38:39:40:41:42:43:44:45 +libstapsdttest.so:libfn:ten:46:47:48:49:50:51:52:53:54:55 +libstapsdttest.so:libfn:eleven:56:57:58:59:60:61:62:63:64:65 +libstapsdttest.so:libfn:twelve:67:68:69:70:71:72:73:74:75:76 + diff --git a/test/unittest/usdt/tst.stapsdt-notes-lib.sh b/test/unittest/usdt/tst.stapsdt-notes-lib.sh new file mode 100755 index 00000000..6fd5808e --- /dev/null +++ b/test/unittest/usdt/tst.stapsdt-notes-lib.sh @@ -0,0 +1,145 @@ +#!/bin/bash +# +# Oracle Linux DTrace. +# Copyright (c) 2025, 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 covers all stapsdt probes fired by the STAP_PROBEn macros. +# Arguments values are checked only for first 10 arguments because +# there is support for arg0 ... arg9 only at this moment. + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="-I${PWD}/test/unittest/usdt" + +DIRNAME="$tmpdir/usdt-notes.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > libstapsdttest.c < + +void +libfn(int argc, char **argv) +{ + if (argc == 0 && argv == 0) + return; + STAP_PROBE(test_prov, zero); + STAP_PROBE1(test_prov, one, argc); + STAP_PROBE2(test_prov, two, 2, 3); + STAP_PROBE3(test_prov, three, 4, 5, 7); + STAP_PROBE4(test_prov, four, 7, 8, 9, 10); + STAP_PROBE5(test_prov, five, 11, 12, 13, 14, 15); + STAP_PROBE6(test_prov, six, 16, 17, 18, 19, 20, 21); + STAP_PROBE7(test_prov, seven, 22, 23, 24, 25, 26, 27, 28); + STAP_PROBE8(test_prov, eight, 29, 30, 31, 32, 33, 34, 35, 36); + STAP_PROBE9(test_prov, nine, 37, 38, 39, 40, 41, 42, 43, 44, 45); + STAP_PROBE10(test_prov, ten, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55); + STAP_PROBE11(test_prov, eleven, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66); + STAP_PROBE12(test_prov, twelve, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78); +} +EOF + +cat > test.c < + +extern void libfn(int argc, char **argv); + +int +main(int argc, char **argv) +{ + libfn(0, 0); + sleep(10); + libfn(argc, argv); + return 0; +} +EOF + +${CC} ${CFLAGS} -c -fpic libstapsdttest.c +${CC} -shared -o libstapsdttest.so libstapsdttest.o +${CC} -L. ${CFLAGS} -o test test.c -lstapsdttest +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi + +export LD_LIBRARY_PATH=.:${LD_LIBRARY_PATH} +LD_LIBRARY_PATH=.:${LD_LIBRARY_PATH} ./test & +PID=$! +sleep 5 +$dtrace -p $PID -qs /dev/stdin < References: <20250130144307.1297654-1-alan.maguire@oracle.com> Message-ID: <20250130144307.1297654-5-alan.maguire@oracle.com> Add a test exercising various arg types supported by stapsdt notes; register values, register + offset and constants. The test generates a binary with probes represented as follows on x86_64: Displaying notes found in: .note.stapsdt Owner Data size Description stapsdt 0x00000048 NT_STAPSDT (SystemTap probe descriptors) Provider: test_prov Name: args Location: 0x0000000000400557, Base: 0x00000000004005f8, Semaphore: 0x0000000000000000 Arguments: -4 at -4(%rbp) 8@%rax 8@%rdx -4@$18 Verify we get expected data for the probe arguments. Signed-off-by: Alan Maguire --- test/unittest/usdt/tst.stapsdt-notes-args.r | 2 + test/unittest/usdt/tst.stapsdt-notes-args.sh | 50 ++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 test/unittest/usdt/tst.stapsdt-notes-args.r create mode 100755 test/unittest/usdt/tst.stapsdt-notes-args.sh diff --git a/test/unittest/usdt/tst.stapsdt-notes-args.r b/test/unittest/usdt/tst.stapsdt-notes-args.r new file mode 100644 index 00000000..42bca19f --- /dev/null +++ b/test/unittest/usdt/tst.stapsdt-notes-args.r @@ -0,0 +1,2 @@ +test:main:args:2:./test:val:18 + diff --git a/test/unittest/usdt/tst.stapsdt-notes-args.sh b/test/unittest/usdt/tst.stapsdt-notes-args.sh new file mode 100755 index 00000000..82097808 --- /dev/null +++ b/test/unittest/usdt/tst.stapsdt-notes-args.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# +# Oracle Linux DTrace. +# Copyright (c) 2025, 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 covers stapsdt probes fired by the STAP_PROBEn macros, +# testing various argument forms (constant, register, deref etc). + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="-I${PWD}/test/unittest/usdt" + +DIRNAME="$tmpdir/usdt-notes.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > test.c < + +int +main(int argc, char **argv) +{ + STAP_PROBE4(test_prov, args, argc, argv[0], argv[1] + 4, 18); +} +EOF + +${CC} ${CFLAGS} -o test test.c +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi + +$dtrace -c './test arg1val' -qs /dev/stdin < References: <2187872c-744b-4b1b-bee9-f504ef6376b6@oracle.com> Message-ID: On Thu, Jan 30, 2025 at 11:03:29AM +0000, Alan Maguire wrote: > On 29/01/2025 07:00, Kris Van Hees wrote: > > Implement d_execargs() to provide task argument string (pr_psargs) > > for the psinfo translator. It takes a task (struct task_struct) as > > argument and returns a string. > > > > psinfo->pr_psargs now simply calls d_execargs(T). > > > > thanks for doing this! I was wondering; would there be a case for > generalizing the d_execargs() to also capture environment variables > (which can be retrieved from the task struct mm struct in a similar > null-separated var=value list)? > > In other words, we pass in the start/end pointers (arg_start, arg_end > for task args, env_start, env_end for env var=value strings). Then the > function would be a more generic, taking a set of strings between these > two start/end addresses and putting them into a single, space-seperated > string (d_coalesce_strings() or something might make sense as a name). Since there are only two cases for this, a generic function would be less useful I think. And honestly, there isn't even a real use case for doing the same for environment variables because those key value pairs, and thus getting them in a single string is less useful. Ideally, we will be able to support pr_argv and pr_envp arrays in the future, but that is still a little uncertain because such pointer arrays do not exist in the Linux task structure. Therefore, to support that part of the psinfo translator we'd need to create it on demand, and that bring up memory mgmt issues (data life time tracking etc). Not fun. > > Signed-off-by: Kris Van Hees > > --- > > bpf/Build | 1 + > > bpf/d_execargs.S | 91 +++++++++++++++++++ > > dlibs/aarch64/5.11/procfs.d | 4 +- > > dlibs/aarch64/5.12/procfs.d | 4 +- > > dlibs/aarch64/5.14/procfs.d | 4 +- > > dlibs/aarch64/5.16/procfs.d | 4 +- > > dlibs/aarch64/5.2/procfs.d | 4 +- > > dlibs/aarch64/5.6/procfs.d | 4 +- > > dlibs/aarch64/6.1/procfs.d | 4 +- > > dlibs/aarch64/6.10/procfs.d | 4 +- > > dlibs/x86_64/5.11/procfs.d | 4 +- > > dlibs/x86_64/5.12/procfs.d | 4 +- > > dlibs/x86_64/5.14/procfs.d | 4 +- > > dlibs/x86_64/5.16/procfs.d | 4 +- > > dlibs/x86_64/5.2/procfs.d | 4 +- > > dlibs/x86_64/5.6/procfs.d | 4 +- > > dlibs/x86_64/6.1/procfs.d | 4 +- > > dlibs/x86_64/6.10/procfs.d | 4 +- > > include/dtrace/dif_defines.h | 7 +- > > libdtrace/dt_bpf.h | 21 +++-- > > libdtrace/dt_cc.c | 33 ++++++- > > libdtrace/dt_cg.c | 9 +- > > libdtrace/dt_dlibs.c | 3 + > > libdtrace/dt_open.c | 2 + > > libdtrace/procfs.d.in | 4 +- > > .../d_execargs/err.D_PROTO_ARG.scalar_arg.d | 16 ++++ > > .../d_execargs/err.D_PROTO_ARG.scalar_arg.r | 4 + > > .../d_execargs/err.D_PROTO_ARG.string_arg.d | 16 ++++ > > .../d_execargs/err.D_PROTO_ARG.string_arg.r | 4 + > > .../d_execargs/err.D_PROTO_ARG.wrong_ptr.d | 16 ++++ > > .../d_execargs/err.D_PROTO_ARG.wrong_ptr.r | 4 + > > .../d_execargs/err.D_PROTO_LEN.missing_arg.d | 16 ++++ > > .../d_execargs/err.D_PROTO_LEN.missing_arg.r | 2 + > > .../err.D_PROTO_LEN.too_many_args.d | 16 ++++ > > .../err.D_PROTO_LEN.too_many_args.r | 2 + > > .../funcs/d_execargs/tst.d_execargs.d | 31 +++++++ > > .../funcs/d_execargs/tst.d_execargs.r | 2 + > > test/unittest/proc/tst.pr_psargs.d | 31 +++++++ > > test/unittest/proc/tst.pr_psargs.r | 9 ++ > > 39 files changed, 339 insertions(+), 65 deletions(-) > > create mode 100644 bpf/d_execargs.S > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > > create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.d > > create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.r > > create mode 100644 test/unittest/proc/tst.pr_psargs.d > > create mode 100644 test/unittest/proc/tst.pr_psargs.r > > > > diff --git a/bpf/Build b/bpf/Build > > index 3e43f4b6..9355326c 100644 > > --- a/bpf/Build > > +++ b/bpf/Build > > @@ -24,6 +24,7 @@ bpf_dlib_SOURCES = \ > > agg_lqbin.c agg_qbin.c \ > > basename.S \ > > cleanpath.S \ > > + d_execargs.S \ > > dirname.S \ > > get_agg.c \ > > get_bvar.c \ > > diff --git a/bpf/d_execargs.S b/bpf/d_execargs.S > > new file mode 100644 > > index 00000000..3a5b1270 > > --- /dev/null > > +++ b/bpf/d_execargs.S > > @@ -0,0 +1,91 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2025, Oracle and/or its affiliates. > > + */ > > + > > +#include > > +#include > > + > > + .text > > + .align 4 > > + .global dt_d_execargs > > +dt_d_execargs: > > + stxdw [%fp+-8], %r1 /* save dctx to stack */ > > + mov %r9, %r3 /* %r9 = args */ > > + > > + mov %r6, %r2 /* set %r6 in case of error */ > > + jeq %r6, 0, .Lerror > > + > > + add %r6, TASK_MM /* ptr = &(T->mm) */ > > + > > + mov %r1, %r9 > > + mov %r2, 8 > > + mov %r3, %r6 > > + call BPF_FUNC_probe_read > > + jne %r0, 0, .Lerror > > + > > + ldxdw %r8, [%r9+0] /* %r8 = T->mm */ > > + jeq %r8, 0, .Lempty > > + mov %r6, %r8 > > + add %r6, TASK_MM_ARG_START /* ptr = &(T->mm->arg_start) */ > > + > > + mov %r1, %r9 > > + mov %r2, 8 > > + mov %r3, %r6 > > + call BPF_FUNC_probe_read > > + jne %r0, 0, .Lerror > > + > > + ldxdw %r7, [%r9+0] /* %r7 = T->mm->arg_start */ > > + mov %r6, %r8 > > + add %r6, TASK_MM_ARG_END /* ptr = &(T->mm->arg_end) */ > > + > > + mov %r1, %r9 > > + mov %r2, 8 > > + mov %r3, %r6 > > + call BPF_FUNC_probe_read > > + jne %r0, 0, .Lerror > > + > > + ldxdw %r6, [%r9+0] /* %r6 = T->mm->arg_end */ > > + > > + mov %r8, %r6 > > + sub %r8, %r7 /* %r8 = len = arg_end - arg_start */ > > + jslt %r8, 2, .Lempty > > + mov %r0, STRSZ > > + jslt %r8, %r0, .Llen_ok > > + mov %r8, %r0 > > +.Llen_ok: > > + > > + /* read data from arg_start to arg_end */ > > + mov %r1, %r9 > > + mov %r2, %r8 > > + mov %r3, %r7 > > + call BPF_FUNC_probe_read /* bpf_probe_read(&args, len + 1, arg_start) */ > > + jne %r0, 0, .Lerror > > + > > + /* loop over args and replace '\0' with ' ' */ > > + mov %r1, %r8 > > + sub %r1, 2 > > +.Lloop: > > + mov %r2, %r9 > > + add %r2, %r1 > > + ldxb %r0, [%r2+0] > > + jne %r0, 0, .Lnot_nil > > + stb [%r2+0], 32 > > +.Lnot_nil: > > + sub %r1, 1 > > + jsge %r1, 0, .Lloop > > + > > +.Ldone: > > + mov %r0, %r9 > > + exit /* return args */ > > +.Lerror: > > + ldxdw %r1, [%fp+-8] > > + mov %r2, PC > > + mov %r3, DTRACEFLT_BADADDR > > + mov %r4, %r6 > > + call dt_probe_error > > +.Lempty: > > + mov %r0, %r9 > > + stb [%r9+0], 0 /* args[0] = 0 */ > > + exit /* return args */ > > + .size dt_d_execargs, .-dt_d_execargs > > diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d > > index 44ec4280..70a43ddf 100644 > > --- a/dlibs/aarch64/5.11/procfs.d > > +++ b/dlibs/aarch64/5.11/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d > > index 44ec4280..70a43ddf 100644 > > --- a/dlibs/aarch64/5.12/procfs.d > > +++ b/dlibs/aarch64/5.12/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d > > index 584ac325..ef27bb70 100644 > > --- a/dlibs/aarch64/5.14/procfs.d > > +++ b/dlibs/aarch64/5.14/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d > > index 5aabc6f1..cad2d2c5 100644 > > --- a/dlibs/aarch64/5.16/procfs.d > > +++ b/dlibs/aarch64/5.16/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d > > index 683ff5a8..6b1b1b9c 100644 > > --- a/dlibs/aarch64/5.2/procfs.d > > +++ b/dlibs/aarch64/5.2/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d > > index 44ec4280..70a43ddf 100644 > > --- a/dlibs/aarch64/5.6/procfs.d > > +++ b/dlibs/aarch64/5.6/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d > > index 5d7873b5..4cb7b77c 100644 > > --- a/dlibs/aarch64/6.1/procfs.d > > +++ b/dlibs/aarch64/6.1/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d > > index 5d7873b5..4cb7b77c 100644 > > --- a/dlibs/aarch64/6.10/procfs.d > > +++ b/dlibs/aarch64/6.10/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d > > index 7274554e..c2be76d8 100644 > > --- a/dlibs/x86_64/5.11/procfs.d > > +++ b/dlibs/x86_64/5.11/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d > > index 7274554e..c2be76d8 100644 > > --- a/dlibs/x86_64/5.12/procfs.d > > +++ b/dlibs/x86_64/5.12/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d > > index d1cf90d3..28fada6d 100644 > > --- a/dlibs/x86_64/5.14/procfs.d > > +++ b/dlibs/x86_64/5.14/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d > > index 5aabc6f1..cad2d2c5 100644 > > --- a/dlibs/x86_64/5.16/procfs.d > > +++ b/dlibs/x86_64/5.16/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d > > index 35538862..08696cf7 100644 > > --- a/dlibs/x86_64/5.2/procfs.d > > +++ b/dlibs/x86_64/5.2/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d > > index 7274554e..c2be76d8 100644 > > --- a/dlibs/x86_64/5.6/procfs.d > > +++ b/dlibs/x86_64/5.6/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d > > index 5d7873b5..4cb7b77c 100644 > > --- a/dlibs/x86_64/6.1/procfs.d > > +++ b/dlibs/x86_64/6.1/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d > > index 5d7873b5..4cb7b77c 100644 > > --- a/dlibs/x86_64/6.10/procfs.d > > +++ b/dlibs/x86_64/6.10/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h > > index c8c1d961..cd785723 100644 > > --- a/include/dtrace/dif_defines.h > > +++ b/include/dtrace/dif_defines.h > > @@ -207,10 +207,11 @@ > > #define DIF_SUBR_INET_NTOP 41 > > #define DIF_SUBR_INET_NTOA 42 > > #define DIF_SUBR_INET_NTOA6 43 > > -#define DIF_SUBR_D_PATH 44 > > -#define DIF_SUBR_LINK_NTOP 45 > > +#define DIF_SUBR_LINK_NTOP 44 > > +#define DIF_SUBR_D_PATH 45 > > +#define DIF_SUBR_D_EXECARGS 46 > > > > -#define DIF_SUBR_MAX 45 > > +#define DIF_SUBR_MAX 46 > > > > typedef uint32_t dif_instr_t; > > > > diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h > > index 6518de66..85934d2d 100644 > > --- a/libdtrace/dt_bpf.h > > +++ b/libdtrace/dt_bpf.h > > @@ -47,15 +47,18 @@ extern "C" { > > #define DT_CONST_TASK_TGID 12 > > #define DT_CONST_TASK_REAL_PARENT 13 > > #define DT_CONST_TASK_COMM 14 > > -#define DT_CONST_MUTEX_OWNER 15 > > -#define DT_CONST_RWLOCK_CNTS 16 > > -#define DT_CONST_DCTX_RODATA 17 > > -#define DT_CONST_RODATA_OFF 18 > > -#define DT_CONST_RODATA_SIZE 19 > > -#define DT_CONST_ZERO_OFF 20 > > -#define DT_CONST_STACK_OFF 21 > > -#define DT_CONST_STACK_SKIP 22 > > -#define DT_CONST_NPROBES 23 > > +#define DT_CONST_TASK_MM 15 > > +#define DT_CONST_TASK_MM_ARG_START 16 > > +#define DT_CONST_TASK_MM_ARG_END 17 > > +#define DT_CONST_MUTEX_OWNER 18 > > +#define DT_CONST_RWLOCK_CNTS 19 > > +#define DT_CONST_DCTX_RODATA 20 > > +#define DT_CONST_RODATA_OFF 21 > > +#define DT_CONST_RODATA_SIZE 22 > > +#define DT_CONST_ZERO_OFF 23 > > +#define DT_CONST_STACK_OFF 24 > > +#define DT_CONST_STACK_SKIP 25 > > +#define DT_CONST_NPROBES 26 > > > > #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 29cfbd84..1dc119ea 100644 > > --- a/libdtrace/dt_cc.c > > +++ b/libdtrace/dt_cc.c > > @@ -1082,7 +1082,8 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, > > case DT_CONST_TASK_PID: > > case DT_CONST_TASK_TGID: > > case DT_CONST_TASK_REAL_PARENT: > > - case DT_CONST_TASK_COMM: { > > + case DT_CONST_TASK_COMM: > > + case DT_CONST_TASK_MM: { > > ctf_file_t *cfp = dtp->dt_shared_ctf; > > ctf_id_t type; > > ctf_membinfo_t ctm; > > @@ -1108,6 +1109,36 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, > > case DT_CONST_TASK_COMM: > > rc = ctf_member_info(cfp, type, "comm", &ctm); > > break; > > + case DT_CONST_TASK_MM: > > + rc = ctf_member_info(cfp, type, "mm", &ctm); > > + break; > > + } > > + if (rc == CTF_ERR) > > + goto err_ctf; > > + nrp->dofr_data = ctm.ctm_offset / NBBY; > > + continue; > > + } > > + case DT_CONST_TASK_MM_ARG_START: > > + case DT_CONST_TASK_MM_ARG_END: { > > + ctf_file_t *cfp = dtp->dt_shared_ctf; > > + ctf_id_t type; > > + ctf_membinfo_t ctm; > > + int rc = 0; > > + > > + if (!cfp) > > + return dt_set_errno(dtp, EDT_NOCTF); > > + > > + type = ctf_lookup_by_name(cfp, "struct mm_struct"); > > + if (type == CTF_ERR) > > + goto err_ctf; > > + > > + switch (idp->di_id) { > > + case DT_CONST_TASK_MM_ARG_START: > > + rc = ctf_member_info(cfp, type, "arg_start", &ctm); > > + break; > > + case DT_CONST_TASK_MM_ARG_END: > > + rc = ctf_member_info(cfp, type, "arg_end", &ctm); > > + break; > > } > > if (rc == CTF_ERR) > > goto err_ctf; > > diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c > > index 6e74b4b0..a1a39f3f 100644 > > --- a/libdtrace/dt_cg.c > > +++ b/libdtrace/dt_cg.c > > @@ -3300,7 +3300,6 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > } > > > > /* built-in variables (note: args[] is handled in dt_cg_array_op) */ > > - /* Special case for arg0 through arg9; encode as args[n] */ > > if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { > > fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); > > idx = idp->di_id - DIF_VAR_ARG0; > > @@ -6661,6 +6660,13 @@ dt_cg_subr_inet_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > tnp->dn_tstring = NULL; > > } > > > > +static void > > +dt_cg_subr_d_execargs(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > +{ > > + dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_d_execargs", 0, > > + DT_IGNOR, 0, DT_IGNOR, 0); > > +} > > + > > static void > > dt_cg_subr_d_path(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > { > > @@ -6758,6 +6764,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = { > > [DIF_SUBR_INET_NTOP] = &dt_cg_subr_inet_ntop, > > [DIF_SUBR_INET_NTOA] = &dt_cg_subr_inet_ntoa, > > [DIF_SUBR_INET_NTOA6] = &dt_cg_subr_inet_ntoa6, > > + [DIF_SUBR_D_EXECARGS] = &dt_cg_subr_d_execargs, > > [DIF_SUBR_D_PATH] = &dt_cg_subr_d_path, > > [DIF_SUBR_LINK_NTOP] = &dt_cg_subr_link_ntop, > > }; > > diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c > > index 07d22afd..9ad4f5e7 100644 > > --- a/libdtrace/dt_dlibs.c > > +++ b/libdtrace/dt_dlibs.c > > @@ -89,6 +89,9 @@ static const dt_ident_t dt_bpf_symbols[] = { > > DT_BPF_SYMBOL_ID(TASK_TGID, DT_IDENT_SCALAR, DT_CONST_TASK_TGID), > > DT_BPF_SYMBOL_ID(TASK_REAL_PARENT, DT_IDENT_SCALAR, DT_CONST_TASK_REAL_PARENT), > > DT_BPF_SYMBOL_ID(TASK_COMM, DT_IDENT_SCALAR, DT_CONST_TASK_COMM), > > + DT_BPF_SYMBOL_ID(TASK_MM, DT_IDENT_SCALAR, DT_CONST_TASK_MM), > > + DT_BPF_SYMBOL_ID(TASK_MM_ARG_START, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_START), > > + DT_BPF_SYMBOL_ID(TASK_MM_ARG_END, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_END), > > DT_BPF_SYMBOL_ID(MUTEX_OWNER, DT_IDENT_SCALAR, DT_CONST_MUTEX_OWNER), > > DT_BPF_SYMBOL_ID(RWLOCK_CNTS, DT_IDENT_SCALAR, DT_CONST_RWLOCK_CNTS), > > DT_BPF_SYMBOL_ID(DCTX_RODATA, DT_IDENT_SCALAR, DT_CONST_DCTX_RODATA), > > diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c > > index a0205887..c8208de6 100644 > > --- a/libdtrace/dt_open.c > > +++ b/libdtrace/dt_open.c > > @@ -138,6 +138,8 @@ static const dt_ident_t _dtrace_globals[] = { > > { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE, > > DTRACE_CLASS_COMMON }, DT_VERS_1_0, > > &dt_idops_type, "vmlinux`struct task_struct *" }, > > +{ "d_execargs", DT_IDENT_FUNC, 0, DIF_SUBR_D_EXECARGS, DT_ATTR_EVOLCMN, > > + DT_VERS_2_0, &dt_idops_func, "string(vmlinux`struct task_struct *)" }, > > { "d_path", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_D_PATH, DT_ATTR_EVOLCMN, > > DT_VERS_1_0, &dt_idops_func, "string(struct path *)" }, > > { "ddi_pathname", DT_IDENT_FUNC, 0, DIF_SUBR_DDI_PATHNAME, > > diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in > > index 038cf69b..e9d50349 100644 > > --- a/libdtrace/procfs.d.in > > +++ b/libdtrace/procfs.d.in > > @@ -179,9 +179,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > > new file mode 100644 > > index 00000000..c707184d > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > > @@ -0,0 +1,16 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: The argument to d_execargs() should be a (struct task_struct *). > > + */ > > + > > +BEGIN > > +{ > > + trace(d_execargs(1)); > > + exit(0); > > +} > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > > new file mode 100644 > > index 00000000..0e9cda07 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > > @@ -0,0 +1,4 @@ > > +-- @@stderr -- > > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > > + prototype: struct task_struct * > > + argument: int > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > > new file mode 100644 > > index 00000000..ba419689 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > > @@ -0,0 +1,16 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: The argument to d_execargs() should be (struct task_struct *). > > + */ > > + > > +BEGIN > > +{ > > + trace(d_execargs("a")); > > + exit(0); > > +} > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > > new file mode 100644 > > index 00000000..ac1c1401 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > > @@ -0,0 +1,4 @@ > > +-- @@stderr -- > > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > > + prototype: struct task_struct * > > + argument: string > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > > new file mode 100644 > > index 00000000..473e35e4 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > > @@ -0,0 +1,16 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: The argument to d_execargs() should be (struct task_struct *). > > + */ > > + > > +BEGIN > > +{ > > + trace(d_execargs(curthread->mm)); > > + exit(0); > > +} > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > > new file mode 100644 > > index 00000000..842371a3 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > > @@ -0,0 +1,4 @@ > > +-- @@stderr -- > > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > > + prototype: struct task_struct * > > + argument: struct mm_struct * > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > > new file mode 100644 > > index 00000000..86b1b237 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > > @@ -0,0 +1,16 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: d_execargs() requires an argument > > + */ > > + > > +BEGIN > > +{ > > + trace(d_execargs()); > > + exit(0); > > +} > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > > new file mode 100644 > > index 00000000..a4fcd162 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > > @@ -0,0 +1,2 @@ > > +-- @@stderr -- > > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 0 args passed, 1 expected > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > > new file mode 100644 > > index 00000000..3add63f6 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > > @@ -0,0 +1,16 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: The d_execargs() subroutine accepts no more than one argument. > > + */ > > + > > +BEGIN > > +{ > > + trace(d_execargs(curthread, 1)); > > + exit(0); > > +} > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > > new file mode 100644 > > index 00000000..f5a982ff > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > > @@ -0,0 +1,2 @@ > > +-- @@stderr -- > > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 2 args passed, 1 expected > > diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.d b/test/unittest/funcs/d_execargs/tst.d_execargs.d > > new file mode 100644 > > index 00000000..b8b141aa > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/tst.d_execargs.d > > @@ -0,0 +1,31 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: d_execargs() provides correct results. > > + */ > > + > > +#pragma D option destructive > > +#pragma D option quiet > > + > > +BEGIN > > +{ > > + mypid = pid; > > + system("/bin/echo TEST"); > > +} > > + > > +proc:::exec-success > > +/progenyof(mypid) && d_execargs(curthread) == "/bin/echo TEST"/ > > +{ > > + trace(d_execargs(curthread)); > > + exit(0); > > +} > > + > > +tick-1s > > +{ > > + exit(1); > > +} > > diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.r b/test/unittest/funcs/d_execargs/tst.d_execargs.r > > new file mode 100644 > > index 00000000..d8ff6689 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/tst.d_execargs.r > > @@ -0,0 +1,2 @@ > > +TEST > > +/bin/echo TEST > > diff --git a/test/unittest/proc/tst.pr_psargs.d b/test/unittest/proc/tst.pr_psargs.d > > new file mode 100644 > > index 00000000..902ac1a3 > > --- /dev/null > > +++ b/test/unittest/proc/tst.pr_psargs.d > > @@ -0,0 +1,31 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: psinfo->pr_psargs provides correct results. > > + */ > > + > > +#pragma D option destructive > > +#pragma D option quiet > > + > > +BEGIN > > +{ > > + mypid = pid; > > + system("/bin/echo TEST"); > > +} > > + > > +proc:::exec-success > > +/progenyof(mypid) && curpsinfo->pr_psargs == "/bin/echo TEST"/ > > +{ > > + trace(curpsinfo->pr_psargs); > > + exit(0); > > +} > > + > > +tick-1s > > +{ > > + exit(1); > > +} > > diff --git a/test/unittest/proc/tst.pr_psargs.r b/test/unittest/proc/tst.pr_psargs.r > > new file mode 100644 > > index 00000000..397c8717 > > --- /dev/null > > +++ b/test/unittest/proc/tst.pr_psargs.r > > @@ -0,0 +1,9 @@ > > +TEST > > + > > + 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef > > + 0: 2f 62 69 6e 2f 65 63 68 6f 20 54 45 53 54 00 00 /bin/echo TEST.. > > + 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > > + 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > > + 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > > + 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > > + From eugene.loh at oracle.com Thu Jan 30 19:22:44 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Thu, 30 Jan 2025 14:22:44 -0500 Subject: [DTrace-devel] [PATCH v2 4/6] procfs: implement d_execargs() for pr_psargs translator support In-Reply-To: References: Message-ID: Reviewed-by: Eugene Loh For test/unittest/funcs/d_execargs/tst.d_execargs.d test/unittest/proc/tst.pr_psargs.d how about a few more arguments?? E.g., system("/bin/echo TEST abcde fghijkl"); (I don't have anything particular in mind that this might catch. Just trying to poke a little harder.) For bpf/d_execargs.S, how about ' ' instead of 32 (in that substitution loop). For bpf/d_execargs.S, a few more comments would be nice.? Per your taste, of course.? But for me, e.g., - There should be a comment with the prototype of the function. ? I think most other bpf/*.S files do this. - One input arg is referred to as "args"... Most other bpf/*.S functions ? refer to this as "dst" or something.? To me that makes more sense ? since, as far as d_execargs() is concerned, this arg is the dest ? location. - Comments refer to T.? This makes sense for the translators I ? guess, but maybe saying it's the task struct or something. - Maybe it'd be helpful to lay out the strategy for how the registers ? are being used?? E.g., %r9 points to the dest location, but meanwhile ? used for scratch space.? %r6 is the pointer to memory we're accessing ? so that, in case of probe_read() error, we know which address to report. On 1/29/25 02:00, Kris Van Hees via DTrace-devel wrote: > Implement d_execargs() to provide task argument string (pr_psargs) > for the psinfo translator. It takes a task (struct task_struct) as > argument and returns a string. > > psinfo->pr_psargs now simply calls d_execargs(T). > > Signed-off-by: Kris Van Hees > --- > bpf/Build | 1 + > bpf/d_execargs.S | 91 +++++++++++++++++++ > dlibs/aarch64/5.11/procfs.d | 4 +- > dlibs/aarch64/5.12/procfs.d | 4 +- > dlibs/aarch64/5.14/procfs.d | 4 +- > dlibs/aarch64/5.16/procfs.d | 4 +- > dlibs/aarch64/5.2/procfs.d | 4 +- > dlibs/aarch64/5.6/procfs.d | 4 +- > dlibs/aarch64/6.1/procfs.d | 4 +- > dlibs/aarch64/6.10/procfs.d | 4 +- > dlibs/x86_64/5.11/procfs.d | 4 +- > dlibs/x86_64/5.12/procfs.d | 4 +- > dlibs/x86_64/5.14/procfs.d | 4 +- > dlibs/x86_64/5.16/procfs.d | 4 +- > dlibs/x86_64/5.2/procfs.d | 4 +- > dlibs/x86_64/5.6/procfs.d | 4 +- > dlibs/x86_64/6.1/procfs.d | 4 +- > dlibs/x86_64/6.10/procfs.d | 4 +- > include/dtrace/dif_defines.h | 7 +- > libdtrace/dt_bpf.h | 21 +++-- > libdtrace/dt_cc.c | 33 ++++++- > libdtrace/dt_cg.c | 9 +- > libdtrace/dt_dlibs.c | 3 + > libdtrace/dt_open.c | 2 + > libdtrace/procfs.d.in | 4 +- > .../d_execargs/err.D_PROTO_ARG.scalar_arg.d | 16 ++++ > .../d_execargs/err.D_PROTO_ARG.scalar_arg.r | 4 + > .../d_execargs/err.D_PROTO_ARG.string_arg.d | 16 ++++ > .../d_execargs/err.D_PROTO_ARG.string_arg.r | 4 + > .../d_execargs/err.D_PROTO_ARG.wrong_ptr.d | 16 ++++ > .../d_execargs/err.D_PROTO_ARG.wrong_ptr.r | 4 + > .../d_execargs/err.D_PROTO_LEN.missing_arg.d | 16 ++++ > .../d_execargs/err.D_PROTO_LEN.missing_arg.r | 2 + > .../err.D_PROTO_LEN.too_many_args.d | 16 ++++ > .../err.D_PROTO_LEN.too_many_args.r | 2 + > .../funcs/d_execargs/tst.d_execargs.d | 31 +++++++ > .../funcs/d_execargs/tst.d_execargs.r | 2 + > test/unittest/proc/tst.pr_psargs.d | 31 +++++++ > test/unittest/proc/tst.pr_psargs.r | 9 ++ > 39 files changed, 339 insertions(+), 65 deletions(-) > create mode 100644 bpf/d_execargs.S > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.d > create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.r > create mode 100644 test/unittest/proc/tst.pr_psargs.d > create mode 100644 test/unittest/proc/tst.pr_psargs.r > > diff --git a/bpf/Build b/bpf/Build > index 3e43f4b6..9355326c 100644 > --- a/bpf/Build > +++ b/bpf/Build > @@ -24,6 +24,7 @@ bpf_dlib_SOURCES = \ > agg_lqbin.c agg_qbin.c \ > basename.S \ > cleanpath.S \ > + d_execargs.S \ > dirname.S \ > get_agg.c \ > get_bvar.c \ > diff --git a/bpf/d_execargs.S b/bpf/d_execargs.S > new file mode 100644 > index 00000000..3a5b1270 > --- /dev/null > +++ b/bpf/d_execargs.S > @@ -0,0 +1,91 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2025, Oracle and/or its affiliates. > + */ > + > +#include > +#include > + > + .text > + .align 4 > + .global dt_d_execargs > +dt_d_execargs: > + stxdw [%fp+-8], %r1 /* save dctx to stack */ > + mov %r9, %r3 /* %r9 = args */ > + > + mov %r6, %r2 /* set %r6 in case of error */ > + jeq %r6, 0, .Lerror > + > + add %r6, TASK_MM /* ptr = &(T->mm) */ > + > + mov %r1, %r9 > + mov %r2, 8 > + mov %r3, %r6 > + call BPF_FUNC_probe_read > + jne %r0, 0, .Lerror > + > + ldxdw %r8, [%r9+0] /* %r8 = T->mm */ > + jeq %r8, 0, .Lempty > + mov %r6, %r8 > + add %r6, TASK_MM_ARG_START /* ptr = &(T->mm->arg_start) */ > + > + mov %r1, %r9 > + mov %r2, 8 > + mov %r3, %r6 > + call BPF_FUNC_probe_read > + jne %r0, 0, .Lerror > + > + ldxdw %r7, [%r9+0] /* %r7 = T->mm->arg_start */ > + mov %r6, %r8 > + add %r6, TASK_MM_ARG_END /* ptr = &(T->mm->arg_end) */ > + > + mov %r1, %r9 > + mov %r2, 8 > + mov %r3, %r6 > + call BPF_FUNC_probe_read > + jne %r0, 0, .Lerror > + > + ldxdw %r6, [%r9+0] /* %r6 = T->mm->arg_end */ > + > + mov %r8, %r6 > + sub %r8, %r7 /* %r8 = len = arg_end - arg_start */ > + jslt %r8, 2, .Lempty > + mov %r0, STRSZ > + jslt %r8, %r0, .Llen_ok > + mov %r8, %r0 > +.Llen_ok: > + > + /* read data from arg_start to arg_end */ > + mov %r1, %r9 > + mov %r2, %r8 > + mov %r3, %r7 > + call BPF_FUNC_probe_read /* bpf_probe_read(&args, len + 1, arg_start) */ > + jne %r0, 0, .Lerror > + > + /* loop over args and replace '\0' with ' ' */ > + mov %r1, %r8 > + sub %r1, 2 > +.Lloop: > + mov %r2, %r9 > + add %r2, %r1 > + ldxb %r0, [%r2+0] > + jne %r0, 0, .Lnot_nil > + stb [%r2+0], 32 > +.Lnot_nil: > + sub %r1, 1 > + jsge %r1, 0, .Lloop > + > +.Ldone: > + mov %r0, %r9 > + exit /* return args */ > +.Lerror: > + ldxdw %r1, [%fp+-8] > + mov %r2, PC > + mov %r3, DTRACEFLT_BADADDR > + mov %r4, %r6 > + call dt_probe_error > +.Lempty: > + mov %r0, %r9 > + stb [%r9+0], 0 /* args[0] = 0 */ > + exit /* return args */ > + .size dt_d_execargs, .-dt_d_execargs > diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d > index 44ec4280..70a43ddf 100644 > --- a/dlibs/aarch64/5.11/procfs.d > +++ b/dlibs/aarch64/5.11/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d > index 44ec4280..70a43ddf 100644 > --- a/dlibs/aarch64/5.12/procfs.d > +++ b/dlibs/aarch64/5.12/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d > index 584ac325..ef27bb70 100644 > --- a/dlibs/aarch64/5.14/procfs.d > +++ b/dlibs/aarch64/5.14/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d > index 5aabc6f1..cad2d2c5 100644 > --- a/dlibs/aarch64/5.16/procfs.d > +++ b/dlibs/aarch64/5.16/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d > index 683ff5a8..6b1b1b9c 100644 > --- a/dlibs/aarch64/5.2/procfs.d > +++ b/dlibs/aarch64/5.2/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d > index 44ec4280..70a43ddf 100644 > --- a/dlibs/aarch64/5.6/procfs.d > +++ b/dlibs/aarch64/5.6/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d > index 5d7873b5..4cb7b77c 100644 > --- a/dlibs/aarch64/6.1/procfs.d > +++ b/dlibs/aarch64/6.1/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d > index 5d7873b5..4cb7b77c 100644 > --- a/dlibs/aarch64/6.10/procfs.d > +++ b/dlibs/aarch64/6.10/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d > index 7274554e..c2be76d8 100644 > --- a/dlibs/x86_64/5.11/procfs.d > +++ b/dlibs/x86_64/5.11/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d > index 7274554e..c2be76d8 100644 > --- a/dlibs/x86_64/5.12/procfs.d > +++ b/dlibs/x86_64/5.12/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d > index d1cf90d3..28fada6d 100644 > --- a/dlibs/x86_64/5.14/procfs.d > +++ b/dlibs/x86_64/5.14/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d > index 5aabc6f1..cad2d2c5 100644 > --- a/dlibs/x86_64/5.16/procfs.d > +++ b/dlibs/x86_64/5.16/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d > index 35538862..08696cf7 100644 > --- a/dlibs/x86_64/5.2/procfs.d > +++ b/dlibs/x86_64/5.2/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d > index 7274554e..c2be76d8 100644 > --- a/dlibs/x86_64/5.6/procfs.d > +++ b/dlibs/x86_64/5.6/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d > index 5d7873b5..4cb7b77c 100644 > --- a/dlibs/x86_64/6.1/procfs.d > +++ b/dlibs/x86_64/6.1/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d > index 5d7873b5..4cb7b77c 100644 > --- a/dlibs/x86_64/6.10/procfs.d > +++ b/dlibs/x86_64/6.10/procfs.d > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h > index c8c1d961..cd785723 100644 > --- a/include/dtrace/dif_defines.h > +++ b/include/dtrace/dif_defines.h > @@ -207,10 +207,11 @@ > #define DIF_SUBR_INET_NTOP 41 > #define DIF_SUBR_INET_NTOA 42 > #define DIF_SUBR_INET_NTOA6 43 > -#define DIF_SUBR_D_PATH 44 > -#define DIF_SUBR_LINK_NTOP 45 > +#define DIF_SUBR_LINK_NTOP 44 > +#define DIF_SUBR_D_PATH 45 > +#define DIF_SUBR_D_EXECARGS 46 > > -#define DIF_SUBR_MAX 45 > +#define DIF_SUBR_MAX 46 > > typedef uint32_t dif_instr_t; > > diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h > index 6518de66..85934d2d 100644 > --- a/libdtrace/dt_bpf.h > +++ b/libdtrace/dt_bpf.h > @@ -47,15 +47,18 @@ extern "C" { > #define DT_CONST_TASK_TGID 12 > #define DT_CONST_TASK_REAL_PARENT 13 > #define DT_CONST_TASK_COMM 14 > -#define DT_CONST_MUTEX_OWNER 15 > -#define DT_CONST_RWLOCK_CNTS 16 > -#define DT_CONST_DCTX_RODATA 17 > -#define DT_CONST_RODATA_OFF 18 > -#define DT_CONST_RODATA_SIZE 19 > -#define DT_CONST_ZERO_OFF 20 > -#define DT_CONST_STACK_OFF 21 > -#define DT_CONST_STACK_SKIP 22 > -#define DT_CONST_NPROBES 23 > +#define DT_CONST_TASK_MM 15 > +#define DT_CONST_TASK_MM_ARG_START 16 > +#define DT_CONST_TASK_MM_ARG_END 17 > +#define DT_CONST_MUTEX_OWNER 18 > +#define DT_CONST_RWLOCK_CNTS 19 > +#define DT_CONST_DCTX_RODATA 20 > +#define DT_CONST_RODATA_OFF 21 > +#define DT_CONST_RODATA_SIZE 22 > +#define DT_CONST_ZERO_OFF 23 > +#define DT_CONST_STACK_OFF 24 > +#define DT_CONST_STACK_SKIP 25 > +#define DT_CONST_NPROBES 26 > > #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 29cfbd84..1dc119ea 100644 > --- a/libdtrace/dt_cc.c > +++ b/libdtrace/dt_cc.c > @@ -1082,7 +1082,8 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, > case DT_CONST_TASK_PID: > case DT_CONST_TASK_TGID: > case DT_CONST_TASK_REAL_PARENT: > - case DT_CONST_TASK_COMM: { > + case DT_CONST_TASK_COMM: > + case DT_CONST_TASK_MM: { > ctf_file_t *cfp = dtp->dt_shared_ctf; > ctf_id_t type; > ctf_membinfo_t ctm; > @@ -1108,6 +1109,36 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, > case DT_CONST_TASK_COMM: > rc = ctf_member_info(cfp, type, "comm", &ctm); > break; > + case DT_CONST_TASK_MM: > + rc = ctf_member_info(cfp, type, "mm", &ctm); > + break; > + } > + if (rc == CTF_ERR) > + goto err_ctf; > + nrp->dofr_data = ctm.ctm_offset / NBBY; > + continue; > + } > + case DT_CONST_TASK_MM_ARG_START: > + case DT_CONST_TASK_MM_ARG_END: { > + ctf_file_t *cfp = dtp->dt_shared_ctf; > + ctf_id_t type; > + ctf_membinfo_t ctm; > + int rc = 0; > + > + if (!cfp) > + return dt_set_errno(dtp, EDT_NOCTF); > + > + type = ctf_lookup_by_name(cfp, "struct mm_struct"); > + if (type == CTF_ERR) > + goto err_ctf; > + > + switch (idp->di_id) { > + case DT_CONST_TASK_MM_ARG_START: > + rc = ctf_member_info(cfp, type, "arg_start", &ctm); > + break; > + case DT_CONST_TASK_MM_ARG_END: > + rc = ctf_member_info(cfp, type, "arg_end", &ctm); > + break; > } > if (rc == CTF_ERR) > goto err_ctf; > diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c > index 6e74b4b0..a1a39f3f 100644 > --- a/libdtrace/dt_cg.c > +++ b/libdtrace/dt_cg.c > @@ -3300,7 +3300,6 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > } > > /* built-in variables (note: args[] is handled in dt_cg_array_op) */ > - /* Special case for arg0 through arg9; encode as args[n] */ > if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { > fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); > idx = idp->di_id - DIF_VAR_ARG0; > @@ -6661,6 +6660,13 @@ dt_cg_subr_inet_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > tnp->dn_tstring = NULL; > } > > +static void > +dt_cg_subr_d_execargs(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > +{ > + dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_d_execargs", 0, > + DT_IGNOR, 0, DT_IGNOR, 0); > +} > + > static void > dt_cg_subr_d_path(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > { > @@ -6758,6 +6764,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = { > [DIF_SUBR_INET_NTOP] = &dt_cg_subr_inet_ntop, > [DIF_SUBR_INET_NTOA] = &dt_cg_subr_inet_ntoa, > [DIF_SUBR_INET_NTOA6] = &dt_cg_subr_inet_ntoa6, > + [DIF_SUBR_D_EXECARGS] = &dt_cg_subr_d_execargs, > [DIF_SUBR_D_PATH] = &dt_cg_subr_d_path, > [DIF_SUBR_LINK_NTOP] = &dt_cg_subr_link_ntop, > }; > diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c > index 07d22afd..9ad4f5e7 100644 > --- a/libdtrace/dt_dlibs.c > +++ b/libdtrace/dt_dlibs.c > @@ -89,6 +89,9 @@ static const dt_ident_t dt_bpf_symbols[] = { > DT_BPF_SYMBOL_ID(TASK_TGID, DT_IDENT_SCALAR, DT_CONST_TASK_TGID), > DT_BPF_SYMBOL_ID(TASK_REAL_PARENT, DT_IDENT_SCALAR, DT_CONST_TASK_REAL_PARENT), > DT_BPF_SYMBOL_ID(TASK_COMM, DT_IDENT_SCALAR, DT_CONST_TASK_COMM), > + DT_BPF_SYMBOL_ID(TASK_MM, DT_IDENT_SCALAR, DT_CONST_TASK_MM), > + DT_BPF_SYMBOL_ID(TASK_MM_ARG_START, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_START), > + DT_BPF_SYMBOL_ID(TASK_MM_ARG_END, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_END), > DT_BPF_SYMBOL_ID(MUTEX_OWNER, DT_IDENT_SCALAR, DT_CONST_MUTEX_OWNER), > DT_BPF_SYMBOL_ID(RWLOCK_CNTS, DT_IDENT_SCALAR, DT_CONST_RWLOCK_CNTS), > DT_BPF_SYMBOL_ID(DCTX_RODATA, DT_IDENT_SCALAR, DT_CONST_DCTX_RODATA), > diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c > index a0205887..c8208de6 100644 > --- a/libdtrace/dt_open.c > +++ b/libdtrace/dt_open.c > @@ -138,6 +138,8 @@ static const dt_ident_t _dtrace_globals[] = { > { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE, > DTRACE_CLASS_COMMON }, DT_VERS_1_0, > &dt_idops_type, "vmlinux`struct task_struct *" }, > +{ "d_execargs", DT_IDENT_FUNC, 0, DIF_SUBR_D_EXECARGS, DT_ATTR_EVOLCMN, > + DT_VERS_2_0, &dt_idops_func, "string(vmlinux`struct task_struct *)" }, > { "d_path", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_D_PATH, DT_ATTR_EVOLCMN, > DT_VERS_1_0, &dt_idops_func, "string(struct path *)" }, > { "ddi_pathname", DT_IDENT_FUNC, 0, DIF_SUBR_DDI_PATHNAME, > diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in > index 038cf69b..e9d50349 100644 > --- a/libdtrace/procfs.d.in > +++ b/libdtrace/procfs.d.in > @@ -179,9 +179,7 @@ translator psinfo_t < struct task_struct *T > { > : (struct tty_struct *)-1; > > pr_fname = T->comm; > -/* > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > - */ > + pr_psargs = d_execargs(T); > pr_wstat = 0; > /* > pr_argc = get_psinfo(T)->__psinfo(argc); > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > new file mode 100644 > index 00000000..c707184d > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > @@ -0,0 +1,16 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: The argument to d_execargs() should be a (struct task_struct *). > + */ > + > +BEGIN > +{ > + trace(d_execargs(1)); > + exit(0); > +} > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > new file mode 100644 > index 00000000..0e9cda07 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > @@ -0,0 +1,4 @@ > +-- @@stderr -- > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > + prototype: struct task_struct * > + argument: int > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > new file mode 100644 > index 00000000..ba419689 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > @@ -0,0 +1,16 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: The argument to d_execargs() should be (struct task_struct *). > + */ > + > +BEGIN > +{ > + trace(d_execargs("a")); > + exit(0); > +} > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > new file mode 100644 > index 00000000..ac1c1401 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > @@ -0,0 +1,4 @@ > +-- @@stderr -- > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > + prototype: struct task_struct * > + argument: string > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > new file mode 100644 > index 00000000..473e35e4 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > @@ -0,0 +1,16 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: The argument to d_execargs() should be (struct task_struct *). > + */ > + > +BEGIN > +{ > + trace(d_execargs(curthread->mm)); > + exit(0); > +} > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > new file mode 100644 > index 00000000..842371a3 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > @@ -0,0 +1,4 @@ > +-- @@stderr -- > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > + prototype: struct task_struct * > + argument: struct mm_struct * > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > new file mode 100644 > index 00000000..86b1b237 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > @@ -0,0 +1,16 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: d_execargs() requires an argument > + */ > + > +BEGIN > +{ > + trace(d_execargs()); > + exit(0); > +} > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > new file mode 100644 > index 00000000..a4fcd162 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > @@ -0,0 +1,2 @@ > +-- @@stderr -- > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 0 args passed, 1 expected > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > new file mode 100644 > index 00000000..3add63f6 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > @@ -0,0 +1,16 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: The d_execargs() subroutine accepts no more than one argument. > + */ > + > +BEGIN > +{ > + trace(d_execargs(curthread, 1)); > + exit(0); > +} > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > new file mode 100644 > index 00000000..f5a982ff > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > @@ -0,0 +1,2 @@ > +-- @@stderr -- > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 2 args passed, 1 expected > diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.d b/test/unittest/funcs/d_execargs/tst.d_execargs.d > new file mode 100644 > index 00000000..b8b141aa > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/tst.d_execargs.d > @@ -0,0 +1,31 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: d_execargs() provides correct results. > + */ > + > +#pragma D option destructive > +#pragma D option quiet > + > +BEGIN > +{ > + mypid = pid; > + system("/bin/echo TEST"); > +} > + > +proc:::exec-success > +/progenyof(mypid) && d_execargs(curthread) == "/bin/echo TEST"/ > +{ > + trace(d_execargs(curthread)); > + exit(0); > +} > + > +tick-1s > +{ > + exit(1); > +} > diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.r b/test/unittest/funcs/d_execargs/tst.d_execargs.r > new file mode 100644 > index 00000000..d8ff6689 > --- /dev/null > +++ b/test/unittest/funcs/d_execargs/tst.d_execargs.r > @@ -0,0 +1,2 @@ > +TEST > +/bin/echo TEST > diff --git a/test/unittest/proc/tst.pr_psargs.d b/test/unittest/proc/tst.pr_psargs.d > new file mode 100644 > index 00000000..902ac1a3 > --- /dev/null > +++ b/test/unittest/proc/tst.pr_psargs.d > @@ -0,0 +1,31 @@ > +/* > + * Oracle Linux DTrace. > + * Copyright (c) 2025, 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. > + */ > + > +/* > + * ASSERTION: psinfo->pr_psargs provides correct results. > + */ > + > +#pragma D option destructive > +#pragma D option quiet > + > +BEGIN > +{ > + mypid = pid; > + system("/bin/echo TEST"); > +} > + > +proc:::exec-success > +/progenyof(mypid) && curpsinfo->pr_psargs == "/bin/echo TEST"/ > +{ > + trace(curpsinfo->pr_psargs); > + exit(0); > +} > + > +tick-1s > +{ > + exit(1); > +} > diff --git a/test/unittest/proc/tst.pr_psargs.r b/test/unittest/proc/tst.pr_psargs.r > new file mode 100644 > index 00000000..397c8717 > --- /dev/null > +++ b/test/unittest/proc/tst.pr_psargs.r > @@ -0,0 +1,9 @@ > +TEST > + > + 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef > + 0: 2f 62 69 6e 2f 65 63 68 6f 20 54 45 53 54 00 00 /bin/echo TEST.. > + 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > + 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > + 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > + 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > + From eugene.loh at oracle.com Thu Jan 30 22:33:45 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Thu, 30 Jan 2025 17:33:45 -0500 Subject: [DTrace-devel] [PATCH 6/6] procfs: populate pr_argc, pr_argv, and pr_envp with default values In-Reply-To: References: Message-ID: <4b5002a1-1c42-9ab1-92f8-3cbb29368de3@oracle.com> My main question is how it is better to provide incorrect results than it is not to have implemented this functionality?? How about just waiting until we implement this functionality?? Isn't it better that a user is told that we haven't implemented this stuff rather than give them results that are incorrect? It is odd that XFAIL is being lifted when we are producing incorrect output, but I suppose that is the burden of some other test/s.? So, okay. Meanwhile, XFAIL is being lifted for test/unittest/builtinvar/tst.psinfo-bug21974606.d even though that change should probably actually appear in an earlier patch, "procfs: implement d_execargs() for pr_psargs translator support", where it starts to XPASS since it depends only on ps_args and not on any of the fields handled in the current patch. On 1/28/25 01:31, Kris Van Hees wrote: > The pr_argc, pr_argv, and pr_envp fields in psinfo are not implemented > yet, so it makes sense to set them to 0 rather than not providing any > translator for them. > > Signed-off-by: Kris Van Hees > --- > dlibs/aarch64/5.11/procfs.d | 8 +++----- > dlibs/aarch64/5.12/procfs.d | 8 +++----- > dlibs/aarch64/5.14/procfs.d | 8 +++----- > dlibs/aarch64/5.16/procfs.d | 8 +++----- > dlibs/aarch64/5.2/procfs.d | 8 +++----- > dlibs/aarch64/5.6/procfs.d | 8 +++----- > dlibs/aarch64/6.1/procfs.d | 8 +++----- > dlibs/aarch64/6.10/procfs.d | 8 +++----- > dlibs/x86_64/5.11/procfs.d | 8 +++----- > dlibs/x86_64/5.12/procfs.d | 8 +++----- > dlibs/x86_64/5.14/procfs.d | 8 +++----- > dlibs/x86_64/5.16/procfs.d | 8 +++----- > dlibs/x86_64/5.2/procfs.d | 8 +++----- > dlibs/x86_64/5.6/procfs.d | 8 +++----- > dlibs/x86_64/6.1/procfs.d | 8 +++----- > dlibs/x86_64/6.10/procfs.d | 8 +++----- > libdtrace/procfs.d.in | 8 +++----- > test/unittest/builtinvar/tst.psinfo-bug21974606.d | 1 - > test/unittest/builtinvar/tst.psinfo-bug22561297.d | 4 +--- > test/unittest/builtinvar/tst.psinfo1.d | 1 - > 20 files changed, 52 insertions(+), 90 deletions(-) > > diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d > index 9c06fe1f..52b2bbe2 100644 > --- a/dlibs/aarch64/5.11/procfs.d > +++ b/dlibs/aarch64/5.11/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d > index 9c06fe1f..52b2bbe2 100644 > --- a/dlibs/aarch64/5.12/procfs.d > +++ b/dlibs/aarch64/5.12/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d > index 2824d137..8c05e299 100644 > --- a/dlibs/aarch64/5.14/procfs.d > +++ b/dlibs/aarch64/5.14/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d > index daf30745..e52ab29a 100644 > --- a/dlibs/aarch64/5.16/procfs.d > +++ b/dlibs/aarch64/5.16/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d > index 3594e5e9..4a95dfd1 100644 > --- a/dlibs/aarch64/5.2/procfs.d > +++ b/dlibs/aarch64/5.2/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d > index 9c06fe1f..52b2bbe2 100644 > --- a/dlibs/aarch64/5.6/procfs.d > +++ b/dlibs/aarch64/5.6/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d > index 2d52f079..4881aa5b 100644 > --- a/dlibs/aarch64/6.1/procfs.d > +++ b/dlibs/aarch64/6.1/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d > index 2d52f079..4881aa5b 100644 > --- a/dlibs/aarch64/6.10/procfs.d > +++ b/dlibs/aarch64/6.10/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d > index 7679db2e..96e55dc1 100644 > --- a/dlibs/x86_64/5.11/procfs.d > +++ b/dlibs/x86_64/5.11/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d > index 7679db2e..96e55dc1 100644 > --- a/dlibs/x86_64/5.12/procfs.d > +++ b/dlibs/x86_64/5.12/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d > index 3a348ebc..8dbf3c01 100644 > --- a/dlibs/x86_64/5.14/procfs.d > +++ b/dlibs/x86_64/5.14/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d > index daf30745..e52ab29a 100644 > --- a/dlibs/x86_64/5.16/procfs.d > +++ b/dlibs/x86_64/5.16/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d > index 6ad926ee..23e05c2c 100644 > --- a/dlibs/x86_64/5.2/procfs.d > +++ b/dlibs/x86_64/5.2/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d > index 7679db2e..96e55dc1 100644 > --- a/dlibs/x86_64/5.6/procfs.d > +++ b/dlibs/x86_64/5.6/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d > index 2d52f079..4881aa5b 100644 > --- a/dlibs/x86_64/6.1/procfs.d > +++ b/dlibs/x86_64/6.1/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d > index 2d52f079..4881aa5b 100644 > --- a/dlibs/x86_64/6.10/procfs.d > +++ b/dlibs/x86_64/6.10/procfs.d > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* Not implemented yet. */ > + pr_argv = 0; /* Not implemented yet. */ > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in > index 827d6b81..d4433be4 100644 > --- a/libdtrace/procfs.d.in > +++ b/libdtrace/procfs.d.in > @@ -181,11 +181,9 @@ translator psinfo_t < struct task_struct *T > { > pr_fname = T->comm; > pr_psargs = d_execargs(T); > pr_wstat = 0; > -/* > - pr_argc = get_psinfo(T)->__psinfo(argc); > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > - */ > + pr_argc = 0; /* not implemented yet */ > + pr_argv = 0; /* not implemented yet */ > + pr_envp = 0; /* not implemented yet */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/test/unittest/builtinvar/tst.psinfo-bug21974606.d b/test/unittest/builtinvar/tst.psinfo-bug21974606.d > index 68d9503d..03857e83 100644 > --- a/test/unittest/builtinvar/tst.psinfo-bug21974606.d > +++ b/test/unittest/builtinvar/tst.psinfo-bug21974606.d > @@ -4,7 +4,6 @@ > * Licensed under the Universal Permissive License v 1.0 as shown at > * http://oss.oracle.com/licenses/upl. > */ > -/* @@xfail: dtv2 */ > > /* > * ASSERTION: > diff --git a/test/unittest/builtinvar/tst.psinfo-bug22561297.d b/test/unittest/builtinvar/tst.psinfo-bug22561297.d > index b9efd0ec..ffccf469 100644 > --- a/test/unittest/builtinvar/tst.psinfo-bug22561297.d > +++ b/test/unittest/builtinvar/tst.psinfo-bug22561297.d > @@ -4,11 +4,9 @@ > * Licensed under the Universal Permissive License v 1.0 as shown at > * http://oss.oracle.com/licenses/upl. > */ > -/* @@xfail: dtv2 */ > > /* > - * ASSERTION: > - * To print psinfo structure values from profile. > + * ASSERTION: To print psinfo structure values from profile. > * > * SECTION: Variables/Built-in Variables > */ > diff --git a/test/unittest/builtinvar/tst.psinfo1.d b/test/unittest/builtinvar/tst.psinfo1.d > index 9e6d5053..7c451598 100644 > --- a/test/unittest/builtinvar/tst.psinfo1.d > +++ b/test/unittest/builtinvar/tst.psinfo1.d > @@ -4,7 +4,6 @@ > * Licensed under the Universal Permissive License v 1.0 as shown at > * http://oss.oracle.com/licenses/upl. > */ > -/* @@xfail: dtv2 */ > > /* > * ASSERTION: From eugene.loh at oracle.com Thu Jan 30 22:53:01 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Thu, 30 Jan 2025 17:53:01 -0500 Subject: [DTrace-devel] [PATCH 3/6] bpf: implement additional relocation types In-Reply-To: References: Message-ID: <961b140b-e70e-4934-3b1c-b8d9ce799518@oracle.com> Reviewed-by: Eugene Loh and an explanation in the commit msg what motivates this patch? On 1/28/25 01:31, Kris Van Hees wrote: > Signed-off-by: Kris Van Hees > --- > include/port.h | 6 ++++++ > libdtrace/dt_as.c | 2 +- > libdtrace/dt_cc.c | 3 ++- > libdtrace/dt_dis.c | 9 ++++++++- > 4 files changed, 17 insertions(+), 3 deletions(-) > > diff --git a/include/port.h b/include/port.h > index 6ce8611e..0aadacb8 100644 > --- a/include/port.h > +++ b/include/port.h > @@ -88,6 +88,12 @@ pid_t gettid(void); > #ifndef R_BPF_64_64 > #define R_BPF_64_64 1 > #endif > +#ifndef R_BPF_64_ABS64 > +#define R_BPF_64_ABS64 2 > +#endif > +#ifndef R_BPF_64_ABS32 > +#define R_BPF_64_ABS32 3 > +#endif > #ifndef R_BPF_64_32 > #define R_BPF_64_32 10 > #endif > diff --git a/libdtrace/dt_as.c b/libdtrace/dt_as.c > index a634b855..d3126f9a 100644 > --- a/libdtrace/dt_as.c > +++ b/libdtrace/dt_as.c > @@ -492,7 +492,7 @@ fail: > case BPF_ST | BPF_MEM | BPF_DW: /* stdw */ > case BPF_ALU64 | BPF_MOV | BPF_K: /* mov */ > case BPF_ALU64 | BPF_ADD | BPF_K: /* add */ > - rp->dofr_type = R_BPF_64_32; > + rp->dofr_type = R_BPF_64_ABS32; > break; > case BPF_LD | BPF_IMM | BPF_DW: /* lddw */ > rp->dofr_type = R_BPF_64_64; > diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c > index eebd923c..29cfbd84 100644 > --- a/libdtrace/dt_cc.c > +++ b/libdtrace/dt_cc.c > @@ -1266,7 +1266,8 @@ dt_link_resolve(dtrace_hdl_t *dtp, dtrace_difo_t *dp) > if (rp->dofr_type == R_BPF_64_64) { > buf[ioff].imm = val & 0xffffffff; > buf[ioff + 1].imm = val >> 32; > - } else if (rp->dofr_type == R_BPF_64_32) > + } else if (rp->dofr_type == R_BPF_64_32 || > + rp->dofr_type == R_BPF_64_ABS32) > buf[ioff].imm = (uint32_t)val; > } > } > diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c > index d983c099..b2e66754 100644 > --- a/libdtrace/dt_dis.c > +++ b/libdtrace/dt_dis.c > @@ -639,6 +639,12 @@ dt_dis_rtab(const char *rtag, const dtrace_difo_t *dp, FILE *fp, > case R_BPF_64_32: > tstr = "R_BPF_INSN_DISP32"; > break; > + case R_BPF_64_ABS64: > + tstr = "R_BPF_DATA_64"; > + break; > + case R_BPF_64_ABS32: > + tstr = "R_BPF_DATA_32"; > + break; > default: > tstr = "R_???"; > } > @@ -853,7 +859,8 @@ dt_dis_difo(const dtrace_difo_t *dp, FILE *fp, const dt_ident_t *idp, > for (; cnt; cnt--, rp++) { > if (rp->dofr_offset < i * sizeof(uint64_t)) > continue; > - if (rp->dofr_offset == i * sizeof(uint64_t)) > + if (rp->dofr_offset >= i * sizeof(uint64_t) && > + rp->dofr_offset < (i + 1) * sizeof(uint64_t)) > rname = dt_difo_getstr(dp, rp->dofr_name); > > break; From kris.van.hees at oracle.com Thu Jan 30 23:03:46 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 30 Jan 2025 18:03:46 -0500 Subject: [DTrace-devel] [PATCH 6/6] procfs: populate pr_argc, pr_argv, and pr_envp with default values In-Reply-To: <4b5002a1-1c42-9ab1-92f8-3cbb29368de3@oracle.com> References: <4b5002a1-1c42-9ab1-92f8-3cbb29368de3@oracle.com> Message-ID: On Thu, Jan 30, 2025 at 05:33:45PM -0500, Eugene Loh wrote: > My main question is how it is better to provide incorrect results than it is > not to have implemented this functionality?? How about just waiting until we > implement this functionality?? Isn't it better that a user is told that we > haven't implemented this stuff rather than give them results that are > incorrect? That is always a balance. Ideally, we should have tests for each independent member of each translator, so that we can do more fine grained testing. But it is not sensible that we do not end up testing any translator members because some are not implemented, whereas providing a default value for them (which we e.g. also do for members in the io translators). That is the precedent I am depending on here. > It is odd that XFAIL is being lifted when we are producing incorrect output, > but I suppose that is the burden of some other test/s.? So, okay. Yes, we need more fine grained tests. > Meanwhile, XFAIL is being lifted for > test/unittest/builtinvar/tst.psinfo-bug21974606.d > even though that change should probably actually appear in an earlier patch, > "procfs: implement d_execargs() for pr_psargs translator support", where it > starts to XPASS since it depends only on ps_args and not on any of the > fields handled in the current patch. Hm, yes, forgot to move that one. Will do. > > On 1/28/25 01:31, Kris Van Hees wrote: > > The pr_argc, pr_argv, and pr_envp fields in psinfo are not implemented > > yet, so it makes sense to set them to 0 rather than not providing any > > translator for them. > > > > Signed-off-by: Kris Van Hees > > --- > > dlibs/aarch64/5.11/procfs.d | 8 +++----- > > dlibs/aarch64/5.12/procfs.d | 8 +++----- > > dlibs/aarch64/5.14/procfs.d | 8 +++----- > > dlibs/aarch64/5.16/procfs.d | 8 +++----- > > dlibs/aarch64/5.2/procfs.d | 8 +++----- > > dlibs/aarch64/5.6/procfs.d | 8 +++----- > > dlibs/aarch64/6.1/procfs.d | 8 +++----- > > dlibs/aarch64/6.10/procfs.d | 8 +++----- > > dlibs/x86_64/5.11/procfs.d | 8 +++----- > > dlibs/x86_64/5.12/procfs.d | 8 +++----- > > dlibs/x86_64/5.14/procfs.d | 8 +++----- > > dlibs/x86_64/5.16/procfs.d | 8 +++----- > > dlibs/x86_64/5.2/procfs.d | 8 +++----- > > dlibs/x86_64/5.6/procfs.d | 8 +++----- > > dlibs/x86_64/6.1/procfs.d | 8 +++----- > > dlibs/x86_64/6.10/procfs.d | 8 +++----- > > libdtrace/procfs.d.in | 8 +++----- > > test/unittest/builtinvar/tst.psinfo-bug21974606.d | 1 - > > test/unittest/builtinvar/tst.psinfo-bug22561297.d | 4 +--- > > test/unittest/builtinvar/tst.psinfo1.d | 1 - > > 20 files changed, 52 insertions(+), 90 deletions(-) > > > > diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d > > index 9c06fe1f..52b2bbe2 100644 > > --- a/dlibs/aarch64/5.11/procfs.d > > +++ b/dlibs/aarch64/5.11/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d > > index 9c06fe1f..52b2bbe2 100644 > > --- a/dlibs/aarch64/5.12/procfs.d > > +++ b/dlibs/aarch64/5.12/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d > > index 2824d137..8c05e299 100644 > > --- a/dlibs/aarch64/5.14/procfs.d > > +++ b/dlibs/aarch64/5.14/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d > > index daf30745..e52ab29a 100644 > > --- a/dlibs/aarch64/5.16/procfs.d > > +++ b/dlibs/aarch64/5.16/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d > > index 3594e5e9..4a95dfd1 100644 > > --- a/dlibs/aarch64/5.2/procfs.d > > +++ b/dlibs/aarch64/5.2/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d > > index 9c06fe1f..52b2bbe2 100644 > > --- a/dlibs/aarch64/5.6/procfs.d > > +++ b/dlibs/aarch64/5.6/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d > > index 2d52f079..4881aa5b 100644 > > --- a/dlibs/aarch64/6.1/procfs.d > > +++ b/dlibs/aarch64/6.1/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d > > index 2d52f079..4881aa5b 100644 > > --- a/dlibs/aarch64/6.10/procfs.d > > +++ b/dlibs/aarch64/6.10/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d > > index 7679db2e..96e55dc1 100644 > > --- a/dlibs/x86_64/5.11/procfs.d > > +++ b/dlibs/x86_64/5.11/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d > > index 7679db2e..96e55dc1 100644 > > --- a/dlibs/x86_64/5.12/procfs.d > > +++ b/dlibs/x86_64/5.12/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d > > index 3a348ebc..8dbf3c01 100644 > > --- a/dlibs/x86_64/5.14/procfs.d > > +++ b/dlibs/x86_64/5.14/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d > > index daf30745..e52ab29a 100644 > > --- a/dlibs/x86_64/5.16/procfs.d > > +++ b/dlibs/x86_64/5.16/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d > > index 6ad926ee..23e05c2c 100644 > > --- a/dlibs/x86_64/5.2/procfs.d > > +++ b/dlibs/x86_64/5.2/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d > > index 7679db2e..96e55dc1 100644 > > --- a/dlibs/x86_64/5.6/procfs.d > > +++ b/dlibs/x86_64/5.6/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d > > index 2d52f079..4881aa5b 100644 > > --- a/dlibs/x86_64/6.1/procfs.d > > +++ b/dlibs/x86_64/6.1/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d > > index 2d52f079..4881aa5b 100644 > > --- a/dlibs/x86_64/6.10/procfs.d > > +++ b/dlibs/x86_64/6.10/procfs.d > > @@ -143,11 +143,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* Not implemented yet. */ > > + pr_argv = 0; /* Not implemented yet. */ > > + pr_envp = 0; /* Not implemented yet. */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in > > index 827d6b81..d4433be4 100644 > > --- a/libdtrace/procfs.d.in > > +++ b/libdtrace/procfs.d.in > > @@ -181,11 +181,9 @@ translator psinfo_t < struct task_struct *T > { > > pr_fname = T->comm; > > pr_psargs = d_execargs(T); > > pr_wstat = 0; > > -/* > > - pr_argc = get_psinfo(T)->__psinfo(argc); > > - pr_argv = (uintptr_t)get_psinfo(T)->__psinfo(argv); > > - pr_envp = (uintptr_t)get_psinfo(T)->__psinfo(envp); > > - */ > > + pr_argc = 0; /* not implemented yet */ > > + pr_argv = 0; /* not implemented yet */ > > + pr_envp = 0; /* not implemented yet */ > > pr_dmodel = PR_MODEL_LP64; > > diff --git a/test/unittest/builtinvar/tst.psinfo-bug21974606.d b/test/unittest/builtinvar/tst.psinfo-bug21974606.d > > index 68d9503d..03857e83 100644 > > --- a/test/unittest/builtinvar/tst.psinfo-bug21974606.d > > +++ b/test/unittest/builtinvar/tst.psinfo-bug21974606.d > > @@ -4,7 +4,6 @@ > > * Licensed under the Universal Permissive License v 1.0 as shown at > > * http://oss.oracle.com/licenses/upl. > > */ > > -/* @@xfail: dtv2 */ > > /* > > * ASSERTION: > > diff --git a/test/unittest/builtinvar/tst.psinfo-bug22561297.d b/test/unittest/builtinvar/tst.psinfo-bug22561297.d > > index b9efd0ec..ffccf469 100644 > > --- a/test/unittest/builtinvar/tst.psinfo-bug22561297.d > > +++ b/test/unittest/builtinvar/tst.psinfo-bug22561297.d > > @@ -4,11 +4,9 @@ > > * Licensed under the Universal Permissive License v 1.0 as shown at > > * http://oss.oracle.com/licenses/upl. > > */ > > -/* @@xfail: dtv2 */ > > /* > > - * ASSERTION: > > - * To print psinfo structure values from profile. > > + * ASSERTION: To print psinfo structure values from profile. > > * > > * SECTION: Variables/Built-in Variables > > */ > > diff --git a/test/unittest/builtinvar/tst.psinfo1.d b/test/unittest/builtinvar/tst.psinfo1.d > > index 9e6d5053..7c451598 100644 > > --- a/test/unittest/builtinvar/tst.psinfo1.d > > +++ b/test/unittest/builtinvar/tst.psinfo1.d > > @@ -4,7 +4,6 @@ > > * Licensed under the Universal Permissive License v 1.0 as shown at > > * http://oss.oracle.com/licenses/upl. > > */ > > -/* @@xfail: dtv2 */ > > /* > > * ASSERTION: From kris.van.hees at oracle.com Thu Jan 30 23:14:55 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 30 Jan 2025 18:14:55 -0500 Subject: [DTrace-devel] [PATCH 3/6] bpf: implement additional relocation types In-Reply-To: <961b140b-e70e-4934-3b1c-b8d9ce799518@oracle.com> References: <961b140b-e70e-4934-3b1c-b8d9ce799518@oracle.com> Message-ID: On Thu, Jan 30, 2025 at 05:53:01PM -0500, Eugene Loh wrote: > Reviewed-by: Eugene Loh > and an explanation in the commit msg what motivates this patch? Sure, though I think it is actually quite obvious for anyone looking at the documented BPF relocation types, and the relocations generated by gcc for BPF code. > On 1/28/25 01:31, Kris Van Hees wrote: > > Signed-off-by: Kris Van Hees > > --- > > include/port.h | 6 ++++++ > > libdtrace/dt_as.c | 2 +- > > libdtrace/dt_cc.c | 3 ++- > > libdtrace/dt_dis.c | 9 ++++++++- > > 4 files changed, 17 insertions(+), 3 deletions(-) > > > > diff --git a/include/port.h b/include/port.h > > index 6ce8611e..0aadacb8 100644 > > --- a/include/port.h > > +++ b/include/port.h > > @@ -88,6 +88,12 @@ pid_t gettid(void); > > #ifndef R_BPF_64_64 > > #define R_BPF_64_64 1 > > #endif > > +#ifndef R_BPF_64_ABS64 > > +#define R_BPF_64_ABS64 2 > > +#endif > > +#ifndef R_BPF_64_ABS32 > > +#define R_BPF_64_ABS32 3 > > +#endif > > #ifndef R_BPF_64_32 > > #define R_BPF_64_32 10 > > #endif > > diff --git a/libdtrace/dt_as.c b/libdtrace/dt_as.c > > index a634b855..d3126f9a 100644 > > --- a/libdtrace/dt_as.c > > +++ b/libdtrace/dt_as.c > > @@ -492,7 +492,7 @@ fail: > > case BPF_ST | BPF_MEM | BPF_DW: /* stdw */ > > case BPF_ALU64 | BPF_MOV | BPF_K: /* mov */ > > case BPF_ALU64 | BPF_ADD | BPF_K: /* add */ > > - rp->dofr_type = R_BPF_64_32; > > + rp->dofr_type = R_BPF_64_ABS32; > > break; > > case BPF_LD | BPF_IMM | BPF_DW: /* lddw */ > > rp->dofr_type = R_BPF_64_64; > > diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c > > index eebd923c..29cfbd84 100644 > > --- a/libdtrace/dt_cc.c > > +++ b/libdtrace/dt_cc.c > > @@ -1266,7 +1266,8 @@ dt_link_resolve(dtrace_hdl_t *dtp, dtrace_difo_t *dp) > > if (rp->dofr_type == R_BPF_64_64) { > > buf[ioff].imm = val & 0xffffffff; > > buf[ioff + 1].imm = val >> 32; > > - } else if (rp->dofr_type == R_BPF_64_32) > > + } else if (rp->dofr_type == R_BPF_64_32 || > > + rp->dofr_type == R_BPF_64_ABS32) > > buf[ioff].imm = (uint32_t)val; > > } > > } > > diff --git a/libdtrace/dt_dis.c b/libdtrace/dt_dis.c > > index d983c099..b2e66754 100644 > > --- a/libdtrace/dt_dis.c > > +++ b/libdtrace/dt_dis.c > > @@ -639,6 +639,12 @@ dt_dis_rtab(const char *rtag, const dtrace_difo_t *dp, FILE *fp, > > case R_BPF_64_32: > > tstr = "R_BPF_INSN_DISP32"; > > break; > > + case R_BPF_64_ABS64: > > + tstr = "R_BPF_DATA_64"; > > + break; > > + case R_BPF_64_ABS32: > > + tstr = "R_BPF_DATA_32"; > > + break; > > default: > > tstr = "R_???"; > > } > > @@ -853,7 +859,8 @@ dt_dis_difo(const dtrace_difo_t *dp, FILE *fp, const dt_ident_t *idp, > > for (; cnt; cnt--, rp++) { > > if (rp->dofr_offset < i * sizeof(uint64_t)) > > continue; > > - if (rp->dofr_offset == i * sizeof(uint64_t)) > > + if (rp->dofr_offset >= i * sizeof(uint64_t) && > > + rp->dofr_offset < (i + 1) * sizeof(uint64_t)) > > rname = dt_difo_getstr(dp, rp->dofr_name); > > break; From eugene.loh at oracle.com Thu Jan 30 23:43:17 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Thu, 30 Jan 2025 18:43:17 -0500 Subject: [DTrace-devel] [PATCH 6/6] procfs: populate pr_argc, pr_argv, and pr_envp with default values In-Reply-To: References: <4b5002a1-1c42-9ab1-92f8-3cbb29368de3@oracle.com> Message-ID: On 1/30/25 18:03, Kris Van Hees wrote: > On Thu, Jan 30, 2025 at 05:33:45PM -0500, Eugene Loh wrote: >> My main question is how it is better to provide incorrect results than it is >> not to have implemented this functionality?? How about just waiting until we >> implement this functionality?? Isn't it better that a user is told that we >> haven't implemented this stuff rather than give them results that are >> incorrect? > That is always a balance. Ideally, we should have tests for each independent > member of each translator, so that we can do more fine grained testing. But > it is not sensible that we do not end up testing any translator members because > some are not implemented, whereas providing a default value for them (which we > e.g. also do for members in the io translators). That is the precedent I am > depending on here. From the user's point of view, the choice is between: *)? the status quo, where an attempt to use one of the unimplemented fields returns a rather nice error message that indicates what the problem is *)? the proposed patch, where we "silently" return incorrect values, leaving the user with incorrect results or wasting time debugging the problem, filing a bug, etc. So, there is hardly a balance here at all for users:? the status quo is far better. From our test suite's point of view, there is a choice between less coverage (some tests XFAIL) and "more coverage", but I question that characterization since the "more coverage" case still doesn't check the correctness of the output.? Anyhow, to the extent that this is a test-suite issue, let's fix it in the test suite instead of polluting user-visible behavior.? Let's not "game the test suite" by modifying dtrace.? The whole set of tst.psinfo*.d tests are in need of overhaul;? so let's improve test coverage by cleaning up the tests rather than feeding users incorrect results. If you'd like me to take a stab at cleaning up tst.psinfo*.d, let me know. >> It is odd that XFAIL is being lifted when we are producing incorrect output, >> but I suppose that is the burden of some other test/s.? So, okay. > Yes, we need more fine grained tests. FWIW, test/unittest/builtinvar/tst.psinfo.d would also XPASS with this patch. >> On 1/28/25 01:31, Kris Van Hees wrote: >>> The pr_argc, pr_argv, and pr_envp fields in psinfo are not implemented >>> yet, so it makes sense to set them to 0 rather than not providing any >>> translator for them. From kris.van.hees at oracle.com Fri Jan 31 00:13:26 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 30 Jan 2025 19:13:26 -0500 Subject: [DTrace-devel] [PATCH 6/6] procfs: populate pr_argc, pr_argv, and pr_envp with default values In-Reply-To: References: <4b5002a1-1c42-9ab1-92f8-3cbb29368de3@oracle.com> Message-ID: Good point - I'll withdraw the patch. We can discuss about the best way to handle the test issues in a later patch (series). On Thu, Jan 30, 2025 at 06:43:17PM -0500, Eugene Loh wrote: > On 1/30/25 18:03, Kris Van Hees wrote: > > > On Thu, Jan 30, 2025 at 05:33:45PM -0500, Eugene Loh wrote: > > > My main question is how it is better to provide incorrect results than it is > > > not to have implemented this functionality?? How about just waiting until we > > > implement this functionality?? Isn't it better that a user is told that we > > > haven't implemented this stuff rather than give them results that are > > > incorrect? > > That is always a balance. Ideally, we should have tests for each independent > > member of each translator, so that we can do more fine grained testing. But > > it is not sensible that we do not end up testing any translator members because > > some are not implemented, whereas providing a default value for them (which we > > e.g. also do for members in the io translators). That is the precedent I am > > depending on here. > > From the user's point of view, the choice is between: > > *)? the status quo, where an attempt to use one of the unimplemented fields > returns a rather nice error message that indicates what the problem is > > *)? the proposed patch, where we "silently" return incorrect values, leaving > the user with incorrect results or wasting time debugging the problem, > filing a bug, etc. > > So, there is hardly a balance here at all for users:? the status quo is far > better. > > From our test suite's point of view, there is a choice between less coverage > (some tests XFAIL) and "more coverage", but I question that characterization > since the "more coverage" case still doesn't check the correctness of the > output.? Anyhow, to the extent that this is a test-suite issue, let's fix it > in the test suite instead of polluting user-visible behavior.? Let's not > "game the test suite" by modifying dtrace.? The whole set of tst.psinfo*.d > tests are in need of overhaul;? so let's improve test coverage by cleaning > up the tests rather than feeding users incorrect results. > > If you'd like me to take a stab at cleaning up tst.psinfo*.d, let me know. > > > > It is odd that XFAIL is being lifted when we are producing incorrect output, > > > but I suppose that is the burden of some other test/s.? So, okay. > > Yes, we need more fine grained tests. > > FWIW, test/unittest/builtinvar/tst.psinfo.d would also XPASS with this > patch. > > > > On 1/28/25 01:31, Kris Van Hees wrote: > > > > The pr_argc, pr_argv, and pr_envp fields in psinfo are not implemented > > > > yet, so it makes sense to set them to 0 rather than not providing any > > > > translator for them. From kris.van.hees at oracle.com Fri Jan 31 16:37:32 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Fri, 31 Jan 2025 11:37:32 -0500 Subject: [DTrace-devel] [PATCH v2 4/6] procfs: implement d_execargs() for pr_psargs translator support In-Reply-To: References: Message-ID: On Thu, Jan 30, 2025 at 02:22:44PM -0500, Eugene Loh wrote: > Reviewed-by: Eugene Loh Thanks. > For > test/unittest/funcs/d_execargs/tst.d_execargs.d > test/unittest/proc/tst.pr_psargs.d > how about a few more arguments?? E.g., > system("/bin/echo TEST abcde fghijkl"); > (I don't have anything particular in mind that this might catch. Just trying > to poke a little harder.) Sure, although it does not really improve the testing because we are looping over all characters, changing '\0' into ' ', except for the last one. If it works for one it works for all, but I also do not mind adding a few extra arguments. > For bpf/d_execargs.S, how about ' ' instead of 32 (in that substitution > loop). OK > For bpf/d_execargs.S, a few more comments would be nice.? Per your taste, of > course.? But for me, e.g., > > - There should be a comment with the prototype of the function. > ? I think most other bpf/*.S files do this. Sure. > - One input arg is referred to as "args"... Most other bpf/*.S functions > ? refer to this as "dst" or something.? To me that makes more sense > ? since, as far as d_execargs() is concerned, this arg is the dest > ? location. I prefer using 'args' here because this is a less generic function. It is not just a destination string but it is a destination string that has a particular meaning/purpose. A more generic name list 'dst' seems to be less useful here, I think. > - Comments refer to T.? This makes sense for the translators I > ? guess, but maybe saying it's the task struct or something. That will be clear from adding the prototype. > - Maybe it'd be helpful to lay out the strategy for how the registers > ? are being used?? E.g., %r9 points to the dest location, but meanwhile > ? used for scratch space.? %r6 is the pointer to memory we're accessing > ? so that, in case of probe_read() error, we know which address to report. The code already includes comments showing what registers are for at the places where they get assigned to. I think adding more would merely add clutter at this point. > > On 1/29/25 02:00, Kris Van Hees via DTrace-devel wrote: > > Implement d_execargs() to provide task argument string (pr_psargs) > > for the psinfo translator. It takes a task (struct task_struct) as > > argument and returns a string. > > > > psinfo->pr_psargs now simply calls d_execargs(T). > > > > Signed-off-by: Kris Van Hees > > --- > > bpf/Build | 1 + > > bpf/d_execargs.S | 91 +++++++++++++++++++ > > dlibs/aarch64/5.11/procfs.d | 4 +- > > dlibs/aarch64/5.12/procfs.d | 4 +- > > dlibs/aarch64/5.14/procfs.d | 4 +- > > dlibs/aarch64/5.16/procfs.d | 4 +- > > dlibs/aarch64/5.2/procfs.d | 4 +- > > dlibs/aarch64/5.6/procfs.d | 4 +- > > dlibs/aarch64/6.1/procfs.d | 4 +- > > dlibs/aarch64/6.10/procfs.d | 4 +- > > dlibs/x86_64/5.11/procfs.d | 4 +- > > dlibs/x86_64/5.12/procfs.d | 4 +- > > dlibs/x86_64/5.14/procfs.d | 4 +- > > dlibs/x86_64/5.16/procfs.d | 4 +- > > dlibs/x86_64/5.2/procfs.d | 4 +- > > dlibs/x86_64/5.6/procfs.d | 4 +- > > dlibs/x86_64/6.1/procfs.d | 4 +- > > dlibs/x86_64/6.10/procfs.d | 4 +- > > include/dtrace/dif_defines.h | 7 +- > > libdtrace/dt_bpf.h | 21 +++-- > > libdtrace/dt_cc.c | 33 ++++++- > > libdtrace/dt_cg.c | 9 +- > > libdtrace/dt_dlibs.c | 3 + > > libdtrace/dt_open.c | 2 + > > libdtrace/procfs.d.in | 4 +- > > .../d_execargs/err.D_PROTO_ARG.scalar_arg.d | 16 ++++ > > .../d_execargs/err.D_PROTO_ARG.scalar_arg.r | 4 + > > .../d_execargs/err.D_PROTO_ARG.string_arg.d | 16 ++++ > > .../d_execargs/err.D_PROTO_ARG.string_arg.r | 4 + > > .../d_execargs/err.D_PROTO_ARG.wrong_ptr.d | 16 ++++ > > .../d_execargs/err.D_PROTO_ARG.wrong_ptr.r | 4 + > > .../d_execargs/err.D_PROTO_LEN.missing_arg.d | 16 ++++ > > .../d_execargs/err.D_PROTO_LEN.missing_arg.r | 2 + > > .../err.D_PROTO_LEN.too_many_args.d | 16 ++++ > > .../err.D_PROTO_LEN.too_many_args.r | 2 + > > .../funcs/d_execargs/tst.d_execargs.d | 31 +++++++ > > .../funcs/d_execargs/tst.d_execargs.r | 2 + > > test/unittest/proc/tst.pr_psargs.d | 31 +++++++ > > test/unittest/proc/tst.pr_psargs.r | 9 ++ > > 39 files changed, 339 insertions(+), 65 deletions(-) > > create mode 100644 bpf/d_execargs.S > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > > create mode 100644 test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > > create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.d > > create mode 100644 test/unittest/funcs/d_execargs/tst.d_execargs.r > > create mode 100644 test/unittest/proc/tst.pr_psargs.d > > create mode 100644 test/unittest/proc/tst.pr_psargs.r > > > > diff --git a/bpf/Build b/bpf/Build > > index 3e43f4b6..9355326c 100644 > > --- a/bpf/Build > > +++ b/bpf/Build > > @@ -24,6 +24,7 @@ bpf_dlib_SOURCES = \ > > agg_lqbin.c agg_qbin.c \ > > basename.S \ > > cleanpath.S \ > > + d_execargs.S \ > > dirname.S \ > > get_agg.c \ > > get_bvar.c \ > > diff --git a/bpf/d_execargs.S b/bpf/d_execargs.S > > new file mode 100644 > > index 00000000..3a5b1270 > > --- /dev/null > > +++ b/bpf/d_execargs.S > > @@ -0,0 +1,91 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (c) 2025, Oracle and/or its affiliates. > > + */ > > + > > +#include > > +#include > > + > > + .text > > + .align 4 > > + .global dt_d_execargs > > +dt_d_execargs: > > + stxdw [%fp+-8], %r1 /* save dctx to stack */ > > + mov %r9, %r3 /* %r9 = args */ > > + > > + mov %r6, %r2 /* set %r6 in case of error */ > > + jeq %r6, 0, .Lerror > > + > > + add %r6, TASK_MM /* ptr = &(T->mm) */ > > + > > + mov %r1, %r9 > > + mov %r2, 8 > > + mov %r3, %r6 > > + call BPF_FUNC_probe_read > > + jne %r0, 0, .Lerror > > + > > + ldxdw %r8, [%r9+0] /* %r8 = T->mm */ > > + jeq %r8, 0, .Lempty > > + mov %r6, %r8 > > + add %r6, TASK_MM_ARG_START /* ptr = &(T->mm->arg_start) */ > > + > > + mov %r1, %r9 > > + mov %r2, 8 > > + mov %r3, %r6 > > + call BPF_FUNC_probe_read > > + jne %r0, 0, .Lerror > > + > > + ldxdw %r7, [%r9+0] /* %r7 = T->mm->arg_start */ > > + mov %r6, %r8 > > + add %r6, TASK_MM_ARG_END /* ptr = &(T->mm->arg_end) */ > > + > > + mov %r1, %r9 > > + mov %r2, 8 > > + mov %r3, %r6 > > + call BPF_FUNC_probe_read > > + jne %r0, 0, .Lerror > > + > > + ldxdw %r6, [%r9+0] /* %r6 = T->mm->arg_end */ > > + > > + mov %r8, %r6 > > + sub %r8, %r7 /* %r8 = len = arg_end - arg_start */ > > + jslt %r8, 2, .Lempty > > + mov %r0, STRSZ > > + jslt %r8, %r0, .Llen_ok > > + mov %r8, %r0 > > +.Llen_ok: > > + > > + /* read data from arg_start to arg_end */ > > + mov %r1, %r9 > > + mov %r2, %r8 > > + mov %r3, %r7 > > + call BPF_FUNC_probe_read /* bpf_probe_read(&args, len + 1, arg_start) */ > > + jne %r0, 0, .Lerror > > + > > + /* loop over args and replace '\0' with ' ' */ > > + mov %r1, %r8 > > + sub %r1, 2 > > +.Lloop: > > + mov %r2, %r9 > > + add %r2, %r1 > > + ldxb %r0, [%r2+0] > > + jne %r0, 0, .Lnot_nil > > + stb [%r2+0], 32 > > +.Lnot_nil: > > + sub %r1, 1 > > + jsge %r1, 0, .Lloop > > + > > +.Ldone: > > + mov %r0, %r9 > > + exit /* return args */ > > +.Lerror: > > + ldxdw %r1, [%fp+-8] > > + mov %r2, PC > > + mov %r3, DTRACEFLT_BADADDR > > + mov %r4, %r6 > > + call dt_probe_error > > +.Lempty: > > + mov %r0, %r9 > > + stb [%r9+0], 0 /* args[0] = 0 */ > > + exit /* return args */ > > + .size dt_d_execargs, .-dt_d_execargs > > diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d > > index 44ec4280..70a43ddf 100644 > > --- a/dlibs/aarch64/5.11/procfs.d > > +++ b/dlibs/aarch64/5.11/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d > > index 44ec4280..70a43ddf 100644 > > --- a/dlibs/aarch64/5.12/procfs.d > > +++ b/dlibs/aarch64/5.12/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d > > index 584ac325..ef27bb70 100644 > > --- a/dlibs/aarch64/5.14/procfs.d > > +++ b/dlibs/aarch64/5.14/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d > > index 5aabc6f1..cad2d2c5 100644 > > --- a/dlibs/aarch64/5.16/procfs.d > > +++ b/dlibs/aarch64/5.16/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d > > index 683ff5a8..6b1b1b9c 100644 > > --- a/dlibs/aarch64/5.2/procfs.d > > +++ b/dlibs/aarch64/5.2/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d > > index 44ec4280..70a43ddf 100644 > > --- a/dlibs/aarch64/5.6/procfs.d > > +++ b/dlibs/aarch64/5.6/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d > > index 5d7873b5..4cb7b77c 100644 > > --- a/dlibs/aarch64/6.1/procfs.d > > +++ b/dlibs/aarch64/6.1/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d > > index 5d7873b5..4cb7b77c 100644 > > --- a/dlibs/aarch64/6.10/procfs.d > > +++ b/dlibs/aarch64/6.10/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d > > index 7274554e..c2be76d8 100644 > > --- a/dlibs/x86_64/5.11/procfs.d > > +++ b/dlibs/x86_64/5.11/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d > > index 7274554e..c2be76d8 100644 > > --- a/dlibs/x86_64/5.12/procfs.d > > +++ b/dlibs/x86_64/5.12/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d > > index d1cf90d3..28fada6d 100644 > > --- a/dlibs/x86_64/5.14/procfs.d > > +++ b/dlibs/x86_64/5.14/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d > > index 5aabc6f1..cad2d2c5 100644 > > --- a/dlibs/x86_64/5.16/procfs.d > > +++ b/dlibs/x86_64/5.16/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d > > index 35538862..08696cf7 100644 > > --- a/dlibs/x86_64/5.2/procfs.d > > +++ b/dlibs/x86_64/5.2/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d > > index 7274554e..c2be76d8 100644 > > --- a/dlibs/x86_64/5.6/procfs.d > > +++ b/dlibs/x86_64/5.6/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d > > index 5d7873b5..4cb7b77c 100644 > > --- a/dlibs/x86_64/6.1/procfs.d > > +++ b/dlibs/x86_64/6.1/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d > > index 5d7873b5..4cb7b77c 100644 > > --- a/dlibs/x86_64/6.10/procfs.d > > +++ b/dlibs/x86_64/6.10/procfs.d > > @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h > > index c8c1d961..cd785723 100644 > > --- a/include/dtrace/dif_defines.h > > +++ b/include/dtrace/dif_defines.h > > @@ -207,10 +207,11 @@ > > #define DIF_SUBR_INET_NTOP 41 > > #define DIF_SUBR_INET_NTOA 42 > > #define DIF_SUBR_INET_NTOA6 43 > > -#define DIF_SUBR_D_PATH 44 > > -#define DIF_SUBR_LINK_NTOP 45 > > +#define DIF_SUBR_LINK_NTOP 44 > > +#define DIF_SUBR_D_PATH 45 > > +#define DIF_SUBR_D_EXECARGS 46 > > -#define DIF_SUBR_MAX 45 > > +#define DIF_SUBR_MAX 46 > > typedef uint32_t dif_instr_t; > > diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h > > index 6518de66..85934d2d 100644 > > --- a/libdtrace/dt_bpf.h > > +++ b/libdtrace/dt_bpf.h > > @@ -47,15 +47,18 @@ extern "C" { > > #define DT_CONST_TASK_TGID 12 > > #define DT_CONST_TASK_REAL_PARENT 13 > > #define DT_CONST_TASK_COMM 14 > > -#define DT_CONST_MUTEX_OWNER 15 > > -#define DT_CONST_RWLOCK_CNTS 16 > > -#define DT_CONST_DCTX_RODATA 17 > > -#define DT_CONST_RODATA_OFF 18 > > -#define DT_CONST_RODATA_SIZE 19 > > -#define DT_CONST_ZERO_OFF 20 > > -#define DT_CONST_STACK_OFF 21 > > -#define DT_CONST_STACK_SKIP 22 > > -#define DT_CONST_NPROBES 23 > > +#define DT_CONST_TASK_MM 15 > > +#define DT_CONST_TASK_MM_ARG_START 16 > > +#define DT_CONST_TASK_MM_ARG_END 17 > > +#define DT_CONST_MUTEX_OWNER 18 > > +#define DT_CONST_RWLOCK_CNTS 19 > > +#define DT_CONST_DCTX_RODATA 20 > > +#define DT_CONST_RODATA_OFF 21 > > +#define DT_CONST_RODATA_SIZE 22 > > +#define DT_CONST_ZERO_OFF 23 > > +#define DT_CONST_STACK_OFF 24 > > +#define DT_CONST_STACK_SKIP 25 > > +#define DT_CONST_NPROBES 26 > > #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 29cfbd84..1dc119ea 100644 > > --- a/libdtrace/dt_cc.c > > +++ b/libdtrace/dt_cc.c > > @@ -1082,7 +1082,8 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, > > case DT_CONST_TASK_PID: > > case DT_CONST_TASK_TGID: > > case DT_CONST_TASK_REAL_PARENT: > > - case DT_CONST_TASK_COMM: { > > + case DT_CONST_TASK_COMM: > > + case DT_CONST_TASK_MM: { > > ctf_file_t *cfp = dtp->dt_shared_ctf; > > ctf_id_t type; > > ctf_membinfo_t ctm; > > @@ -1108,6 +1109,36 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, > > case DT_CONST_TASK_COMM: > > rc = ctf_member_info(cfp, type, "comm", &ctm); > > break; > > + case DT_CONST_TASK_MM: > > + rc = ctf_member_info(cfp, type, "mm", &ctm); > > + break; > > + } > > + if (rc == CTF_ERR) > > + goto err_ctf; > > + nrp->dofr_data = ctm.ctm_offset / NBBY; > > + continue; > > + } > > + case DT_CONST_TASK_MM_ARG_START: > > + case DT_CONST_TASK_MM_ARG_END: { > > + ctf_file_t *cfp = dtp->dt_shared_ctf; > > + ctf_id_t type; > > + ctf_membinfo_t ctm; > > + int rc = 0; > > + > > + if (!cfp) > > + return dt_set_errno(dtp, EDT_NOCTF); > > + > > + type = ctf_lookup_by_name(cfp, "struct mm_struct"); > > + if (type == CTF_ERR) > > + goto err_ctf; > > + > > + switch (idp->di_id) { > > + case DT_CONST_TASK_MM_ARG_START: > > + rc = ctf_member_info(cfp, type, "arg_start", &ctm); > > + break; > > + case DT_CONST_TASK_MM_ARG_END: > > + rc = ctf_member_info(cfp, type, "arg_end", &ctm); > > + break; > > } > > if (rc == CTF_ERR) > > goto err_ctf; > > diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c > > index 6e74b4b0..a1a39f3f 100644 > > --- a/libdtrace/dt_cg.c > > +++ b/libdtrace/dt_cg.c > > @@ -3300,7 +3300,6 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > } > > /* built-in variables (note: args[] is handled in dt_cg_array_op) */ > > - /* Special case for arg0 through arg9; encode as args[n] */ > > if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { > > fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); > > idx = idp->di_id - DIF_VAR_ARG0; > > @@ -6661,6 +6660,13 @@ dt_cg_subr_inet_ntop(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > tnp->dn_tstring = NULL; > > } > > +static void > > +dt_cg_subr_d_execargs(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > +{ > > + dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_d_execargs", 0, > > + DT_IGNOR, 0, DT_IGNOR, 0); > > +} > > + > > static void > > dt_cg_subr_d_path(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) > > { > > @@ -6758,6 +6764,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = { > > [DIF_SUBR_INET_NTOP] = &dt_cg_subr_inet_ntop, > > [DIF_SUBR_INET_NTOA] = &dt_cg_subr_inet_ntoa, > > [DIF_SUBR_INET_NTOA6] = &dt_cg_subr_inet_ntoa6, > > + [DIF_SUBR_D_EXECARGS] = &dt_cg_subr_d_execargs, > > [DIF_SUBR_D_PATH] = &dt_cg_subr_d_path, > > [DIF_SUBR_LINK_NTOP] = &dt_cg_subr_link_ntop, > > }; > > diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c > > index 07d22afd..9ad4f5e7 100644 > > --- a/libdtrace/dt_dlibs.c > > +++ b/libdtrace/dt_dlibs.c > > @@ -89,6 +89,9 @@ static const dt_ident_t dt_bpf_symbols[] = { > > DT_BPF_SYMBOL_ID(TASK_TGID, DT_IDENT_SCALAR, DT_CONST_TASK_TGID), > > DT_BPF_SYMBOL_ID(TASK_REAL_PARENT, DT_IDENT_SCALAR, DT_CONST_TASK_REAL_PARENT), > > DT_BPF_SYMBOL_ID(TASK_COMM, DT_IDENT_SCALAR, DT_CONST_TASK_COMM), > > + DT_BPF_SYMBOL_ID(TASK_MM, DT_IDENT_SCALAR, DT_CONST_TASK_MM), > > + DT_BPF_SYMBOL_ID(TASK_MM_ARG_START, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_START), > > + DT_BPF_SYMBOL_ID(TASK_MM_ARG_END, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_END), > > DT_BPF_SYMBOL_ID(MUTEX_OWNER, DT_IDENT_SCALAR, DT_CONST_MUTEX_OWNER), > > DT_BPF_SYMBOL_ID(RWLOCK_CNTS, DT_IDENT_SCALAR, DT_CONST_RWLOCK_CNTS), > > DT_BPF_SYMBOL_ID(DCTX_RODATA, DT_IDENT_SCALAR, DT_CONST_DCTX_RODATA), > > diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c > > index a0205887..c8208de6 100644 > > --- a/libdtrace/dt_open.c > > +++ b/libdtrace/dt_open.c > > @@ -138,6 +138,8 @@ static const dt_ident_t _dtrace_globals[] = { > > { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE, > > DTRACE_CLASS_COMMON }, DT_VERS_1_0, > > &dt_idops_type, "vmlinux`struct task_struct *" }, > > +{ "d_execargs", DT_IDENT_FUNC, 0, DIF_SUBR_D_EXECARGS, DT_ATTR_EVOLCMN, > > + DT_VERS_2_0, &dt_idops_func, "string(vmlinux`struct task_struct *)" }, > > { "d_path", DT_IDENT_FUNC, DT_IDFLG_DPTR, DIF_SUBR_D_PATH, DT_ATTR_EVOLCMN, > > DT_VERS_1_0, &dt_idops_func, "string(struct path *)" }, > > { "ddi_pathname", DT_IDENT_FUNC, 0, DIF_SUBR_DDI_PATHNAME, > > diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in > > index 038cf69b..e9d50349 100644 > > --- a/libdtrace/procfs.d.in > > +++ b/libdtrace/procfs.d.in > > @@ -179,9 +179,7 @@ translator psinfo_t < struct task_struct *T > { > > : (struct tty_struct *)-1; > > pr_fname = T->comm; > > -/* > > - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); > > - */ > > + pr_psargs = d_execargs(T); > > pr_wstat = 0; > > /* > > pr_argc = get_psinfo(T)->__psinfo(argc); > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > > new file mode 100644 > > index 00000000..c707184d > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d > > @@ -0,0 +1,16 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: The argument to d_execargs() should be a (struct task_struct *). > > + */ > > + > > +BEGIN > > +{ > > + trace(d_execargs(1)); > > + exit(0); > > +} > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > > new file mode 100644 > > index 00000000..0e9cda07 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.r > > @@ -0,0 +1,4 @@ > > +-- @@stderr -- > > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.scalar_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > > + prototype: struct task_struct * > > + argument: int > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > > new file mode 100644 > > index 00000000..ba419689 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d > > @@ -0,0 +1,16 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: The argument to d_execargs() should be (struct task_struct *). > > + */ > > + > > +BEGIN > > +{ > > + trace(d_execargs("a")); > > + exit(0); > > +} > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > > new file mode 100644 > > index 00000000..ac1c1401 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.r > > @@ -0,0 +1,4 @@ > > +-- @@stderr -- > > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.string_arg.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > > + prototype: struct task_struct * > > + argument: string > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > > new file mode 100644 > > index 00000000..473e35e4 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d > > @@ -0,0 +1,16 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: The argument to d_execargs() should be (struct task_struct *). > > + */ > > + > > +BEGIN > > +{ > > + trace(d_execargs(curthread->mm)); > > + exit(0); > > +} > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > > new file mode 100644 > > index 00000000..842371a3 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.r > > @@ -0,0 +1,4 @@ > > +-- @@stderr -- > > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_ARG.wrong_ptr.d: [D_PROTO_ARG] line 14: d_execargs( ) argument #1 is incompatible with prototype: > > + prototype: struct task_struct * > > + argument: struct mm_struct * > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > > new file mode 100644 > > index 00000000..86b1b237 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d > > @@ -0,0 +1,16 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: d_execargs() requires an argument > > + */ > > + > > +BEGIN > > +{ > > + trace(d_execargs()); > > + exit(0); > > +} > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > > new file mode 100644 > > index 00000000..a4fcd162 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.r > > @@ -0,0 +1,2 @@ > > +-- @@stderr -- > > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.missing_arg.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 0 args passed, 1 expected > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > > new file mode 100644 > > index 00000000..3add63f6 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d > > @@ -0,0 +1,16 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: The d_execargs() subroutine accepts no more than one argument. > > + */ > > + > > +BEGIN > > +{ > > + trace(d_execargs(curthread, 1)); > > + exit(0); > > +} > > diff --git a/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > > new file mode 100644 > > index 00000000..f5a982ff > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.r > > @@ -0,0 +1,2 @@ > > +-- @@stderr -- > > +dtrace: failed to compile script test/unittest/funcs/d_execargs/err.D_PROTO_LEN.too_many_args.d: [D_PROTO_LEN] line 14: d_execargs( ) prototype mismatch: 2 args passed, 1 expected > > diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.d b/test/unittest/funcs/d_execargs/tst.d_execargs.d > > new file mode 100644 > > index 00000000..b8b141aa > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/tst.d_execargs.d > > @@ -0,0 +1,31 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: d_execargs() provides correct results. > > + */ > > + > > +#pragma D option destructive > > +#pragma D option quiet > > + > > +BEGIN > > +{ > > + mypid = pid; > > + system("/bin/echo TEST"); > > +} > > + > > +proc:::exec-success > > +/progenyof(mypid) && d_execargs(curthread) == "/bin/echo TEST"/ > > +{ > > + trace(d_execargs(curthread)); > > + exit(0); > > +} > > + > > +tick-1s > > +{ > > + exit(1); > > +} > > diff --git a/test/unittest/funcs/d_execargs/tst.d_execargs.r b/test/unittest/funcs/d_execargs/tst.d_execargs.r > > new file mode 100644 > > index 00000000..d8ff6689 > > --- /dev/null > > +++ b/test/unittest/funcs/d_execargs/tst.d_execargs.r > > @@ -0,0 +1,2 @@ > > +TEST > > +/bin/echo TEST > > diff --git a/test/unittest/proc/tst.pr_psargs.d b/test/unittest/proc/tst.pr_psargs.d > > new file mode 100644 > > index 00000000..902ac1a3 > > --- /dev/null > > +++ b/test/unittest/proc/tst.pr_psargs.d > > @@ -0,0 +1,31 @@ > > +/* > > + * Oracle Linux DTrace. > > + * Copyright (c) 2025, 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. > > + */ > > + > > +/* > > + * ASSERTION: psinfo->pr_psargs provides correct results. > > + */ > > + > > +#pragma D option destructive > > +#pragma D option quiet > > + > > +BEGIN > > +{ > > + mypid = pid; > > + system("/bin/echo TEST"); > > +} > > + > > +proc:::exec-success > > +/progenyof(mypid) && curpsinfo->pr_psargs == "/bin/echo TEST"/ > > +{ > > + trace(curpsinfo->pr_psargs); > > + exit(0); > > +} > > + > > +tick-1s > > +{ > > + exit(1); > > +} > > diff --git a/test/unittest/proc/tst.pr_psargs.r b/test/unittest/proc/tst.pr_psargs.r > > new file mode 100644 > > index 00000000..397c8717 > > --- /dev/null > > +++ b/test/unittest/proc/tst.pr_psargs.r > > @@ -0,0 +1,9 @@ > > +TEST > > + > > + 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef > > + 0: 2f 62 69 6e 2f 65 63 68 6f 20 54 45 53 54 00 00 /bin/echo TEST.. > > + 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > > + 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > > + 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > > + 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ > > + From eugene.loh at oracle.com Fri Jan 31 20:29:50 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Fri, 31 Jan 2025 15:29:50 -0500 Subject: [DTrace-devel] [PATCH v2 4/6] procfs: implement d_execargs() for pr_psargs translator support In-Reply-To: References: Message-ID: On 1/31/25 11:37, Kris Van Hees wrote: > On Thu, Jan 30, 2025 at 02:22:44PM -0500, Eugene Loh wrote: >> For >> test/unittest/funcs/d_execargs/tst.d_execargs.d >> test/unittest/proc/tst.pr_psargs.d >> how about a few more arguments?? E.g., >> system("/bin/echo TEST abcde fghijkl"); >> (I don't have anything particular in mind that this might catch. Just trying >> to poke a little harder.) > Sure, although it does not really improve the testing because we are looping > over all characters, changing '\0' into ' ', except for the last one. If it > works for one it works for all, but I also do not mind adding a few extra > arguments. Cool.? Again, I have nothing particular in mind that this would stress -- if it catches something, it would be something unforeseen. Incidentally, I hadn't run proc/tst.pr_args.d.? I just tried: *)? On ARM UEK6 (OL7 and OL8), I got dtrace: error in dt_clause_1 for probe ID 98979 (proc:vmlinux::exec-success): invalid address (0xfffff895fa9f) at BPF pc 934 dtrace: error in dt_clause_1 for probe ID 98979 (proc:vmlinux::exec-success): invalid address (0xffffcb24faa0) at BPF pc 934 Maybe UEK6 is not of interest, but there you have it.? Some copyin thing?? I don't know. *)? On most platforms, I got ???????????? 0? 1? 2? 3? 4? 5? 6? 7? 8? 9? a? b? c? d? e? f 0123456789abcdef ???????? 0: 2f 62 69 6e 2f 65 63 68 6f 20 54 45 53 54 00 20 /bin/echo TEST. ??????? 10: 54 45 53 54 00 00 00 00 00 00 00 00 00 00 00 00 TEST............ ??????? 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ??????? 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ??????? 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ I do not know where those extra chars are coming from, but the test is exposing itself to printing out garbage in any case.? Maybe use printf() instead of trace so that we do not print out the buffer past the NUL char (and get more compact and readable output to boot)? From kris.van.hees at oracle.com Fri Jan 24 07:17:54 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Fri, 24 Jan 2025 02:17:54 -0500 Subject: [DTrace-devel] [PATCH v3] procfs: implement execargs for pr_psargs translator support Message-ID: Implement a new execargs built-in variable to provide the ps-style argument string for the current task. It is used in the psinfo translator for the pr_psargs member. Due to BPF limitations, it is only possible to retrieve this information for the current task. The data is stored in the task's address space, and the only BPF helper that can access data in another task's address space is not allowed to be used in non-sleepable programs (such as tracing programs). Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh --- bpf/Build | 1 + bpf/bvar_execargs.S | 97 +++++++++++++++++++ dlibs/aarch64/5.11/procfs.d | 4 +- dlibs/aarch64/5.12/procfs.d | 4 +- dlibs/aarch64/5.14/procfs.d | 4 +- dlibs/aarch64/5.16/procfs.d | 4 +- dlibs/aarch64/5.2/procfs.d | 4 +- dlibs/aarch64/5.6/procfs.d | 4 +- dlibs/aarch64/6.1/procfs.d | 4 +- dlibs/aarch64/6.10/procfs.d | 4 +- dlibs/x86_64/5.11/procfs.d | 5 +- dlibs/x86_64/5.12/procfs.d | 5 +- dlibs/x86_64/5.14/procfs.d | 5 +- dlibs/x86_64/5.16/procfs.d | 5 +- dlibs/x86_64/5.2/procfs.d | 5 +- dlibs/x86_64/5.6/procfs.d | 5 +- dlibs/x86_64/6.1/procfs.d | 5 +- dlibs/x86_64/6.10/procfs.d | 5 +- include/dtrace/dif_defines.h | 1 + libdtrace/dt_bpf.h | 21 ++-- libdtrace/dt_cc.c | 33 ++++++- libdtrace/dt_cg.c | 26 ++++- libdtrace/dt_dlibs.c | 3 + libdtrace/dt_open.c | 2 + libdtrace/procfs.d.in | 5 +- .../builtinvar/tst.psinfo-bug21974606.d | 4 +- .../builtinvar/tst.psinfo-bug22561297.d | 8 +- test/unittest/builtinvar/tst.psinfo.d | 8 +- test/unittest/builtinvar/tst.psinfo1.d | 8 +- test/unittest/proc/tst.pr_psargs.d | 36 +++++++ test/unittest/proc/tst.pr_psargs.r | 2 + test/unittest/proc/tst.pr_psargs_other_task.d | 37 +++++++ test/unittest/proc/tst.pr_psargs_other_task.r | 9 ++ test/unittest/variables/bvar/tst.execargs.d | 23 +++++ 34 files changed, 319 insertions(+), 77 deletions(-) create mode 100644 bpf/bvar_execargs.S create mode 100644 test/unittest/proc/tst.pr_psargs.d create mode 100644 test/unittest/proc/tst.pr_psargs.r create mode 100644 test/unittest/proc/tst.pr_psargs_other_task.d create mode 100644 test/unittest/proc/tst.pr_psargs_other_task.r create mode 100644 test/unittest/variables/bvar/tst.execargs.d diff --git a/bpf/Build b/bpf/Build index 3e43f4b6..a9fb100a 100644 --- a/bpf/Build +++ b/bpf/Build @@ -23,6 +23,7 @@ bpf_dlib_SRCDEPS = $(objdir)/include/.dir.stamp $(objdir)/include/bpf_asm_helper bpf_dlib_SOURCES = \ agg_lqbin.c agg_qbin.c \ basename.S \ + bvar_execargs.S \ cleanpath.S \ dirname.S \ get_agg.c \ diff --git a/bpf/bvar_execargs.S b/bpf/bvar_execargs.S new file mode 100644 index 00000000..1c47cafb --- /dev/null +++ b/bpf/bvar_execargs.S @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025, Oracle and/or its affiliates. + */ + +#include +#include + +/* + * uint64_t dt_bvar_execargs(const dt_dctx_t *dctx, char *args) + */ + .text + .align 4 + .global dt_bvar_execargs + .type dt_bvar_execargs, @function +dt_bvar_execargs: + stxdw [%fp+-8], %r1 /* save dctx to stack */ + mov %r9, %r2 /* %r9 = args */ + + mov %r6, 0 /* set %r6 in case of error */ + call BPF_FUNC_get_current_task /* get curthread (T) */ + jeq %r0, 0, .Lerror + + mov %r6, %r0 + add %r6, TASK_MM /* %r6 = &(T->mm) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r8, [%r9+0] /* %r8 = T->mm */ + jeq %r8, 0, .Lempty + mov %r6, %r8 + add %r6, TASK_MM_ARG_START /* ptr = &(T->mm->arg_start) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r7, [%r9+0] /* %r7 = T->mm->arg_start */ + mov %r6, %r8 + add %r6, TASK_MM_ARG_END /* ptr = &(T->mm->arg_end) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r6, [%r9+0] /* %r6 = T->mm->arg_end */ + + mov %r8, %r6 + sub %r8, %r7 /* %r8 = len = arg_end - arg_start */ + jslt %r8, 2, .Lempty + mov %r0, STRSZ + jslt %r8, %r0, .Llen_ok + mov %r8, %r0 +.Llen_ok: + + /* read data from arg_start to arg_end */ + mov %r1, %r9 + mov %r2, %r8 + mov %r3, %r7 + call BPF_FUNC_probe_read /* bpf_probe_read(&args, len + 1, arg_start) */ + jne %r0, 0, .Lerror + + /* loop over args and replace '\0' with ' ' */ + mov %r1, %r8 + sub %r1, 2 +.Lloop: + mov %r2, %r9 + add %r2, %r1 + ldxb %r0, [%r2+0] + jne %r0, 0, .Lnot_nil + stb [%r2+0], 32 +.Lnot_nil: + sub %r1, 1 + jsge %r1, 0, .Lloop + +.Ldone: + mov %r0, %r9 + exit /* return args */ +.Lerror: + ldxdw %r1, [%fp+-8] + mov %r2, PC + mov %r3, DTRACEFLT_BADADDR + mov %r4, %r6 + call dt_probe_error +.Lempty: + mov %r0, %r9 + stb [%r9+0], 0 /* args[0] = 0 */ + exit /* return args */ + .size dt_bvar_execargs, .-dt_bvar_execargs diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.11/procfs.d +++ b/dlibs/aarch64/5.11/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.12/procfs.d +++ b/dlibs/aarch64/5.12/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d index 584ac325..ef27bb70 100644 --- a/dlibs/aarch64/5.14/procfs.d +++ b/dlibs/aarch64/5.14/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d index 5aabc6f1..cad2d2c5 100644 --- a/dlibs/aarch64/5.16/procfs.d +++ b/dlibs/aarch64/5.16/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d index 683ff5a8..6b1b1b9c 100644 --- a/dlibs/aarch64/5.2/procfs.d +++ b/dlibs/aarch64/5.2/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.6/procfs.d +++ b/dlibs/aarch64/5.6/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/aarch64/6.1/procfs.d +++ b/dlibs/aarch64/6.1/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/aarch64/6.10/procfs.d +++ b/dlibs/aarch64/6.10/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d index 7274554e..f0071440 100644 --- a/dlibs/x86_64/5.11/procfs.d +++ b/dlibs/x86_64/5.11/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d index 7274554e..f0071440 100644 --- a/dlibs/x86_64/5.12/procfs.d +++ b/dlibs/x86_64/5.12/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d index d1cf90d3..17f95e5c 100644 --- a/dlibs/x86_64/5.14/procfs.d +++ b/dlibs/x86_64/5.14/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d index 5aabc6f1..f924c2a1 100644 --- a/dlibs/x86_64/5.16/procfs.d +++ b/dlibs/x86_64/5.16/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d index 35538862..36608ad0 100644 --- a/dlibs/x86_64/5.2/procfs.d +++ b/dlibs/x86_64/5.2/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d index 7274554e..f0071440 100644 --- a/dlibs/x86_64/5.6/procfs.d +++ b/dlibs/x86_64/5.6/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d index 5d7873b5..a3d7f949 100644 --- a/dlibs/x86_64/6.1/procfs.d +++ b/dlibs/x86_64/6.1/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d index 5d7873b5..a3d7f949 100644 --- a/dlibs/x86_64/6.10/procfs.d +++ b/dlibs/x86_64/6.10/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h index c8c1d961..9f6e3b55 100644 --- a/include/dtrace/dif_defines.h +++ b/include/dtrace/dif_defines.h @@ -162,6 +162,7 @@ #define DIF_VAR_GID 0x011f #define DIF_VAR_ERRNO 0x0120 #define DIF_VAR_CURCPU 0x0121 +#define DIF_VAR_EXECARGS 0x0122 #define DIF_SUBR_RAND 0 #define DIF_SUBR_MUTEX_OWNED 1 diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h index 6518de66..85934d2d 100644 --- a/libdtrace/dt_bpf.h +++ b/libdtrace/dt_bpf.h @@ -47,15 +47,18 @@ extern "C" { #define DT_CONST_TASK_TGID 12 #define DT_CONST_TASK_REAL_PARENT 13 #define DT_CONST_TASK_COMM 14 -#define DT_CONST_MUTEX_OWNER 15 -#define DT_CONST_RWLOCK_CNTS 16 -#define DT_CONST_DCTX_RODATA 17 -#define DT_CONST_RODATA_OFF 18 -#define DT_CONST_RODATA_SIZE 19 -#define DT_CONST_ZERO_OFF 20 -#define DT_CONST_STACK_OFF 21 -#define DT_CONST_STACK_SKIP 22 -#define DT_CONST_NPROBES 23 +#define DT_CONST_TASK_MM 15 +#define DT_CONST_TASK_MM_ARG_START 16 +#define DT_CONST_TASK_MM_ARG_END 17 +#define DT_CONST_MUTEX_OWNER 18 +#define DT_CONST_RWLOCK_CNTS 19 +#define DT_CONST_DCTX_RODATA 20 +#define DT_CONST_RODATA_OFF 21 +#define DT_CONST_RODATA_SIZE 22 +#define DT_CONST_ZERO_OFF 23 +#define DT_CONST_STACK_OFF 24 +#define DT_CONST_STACK_SKIP 25 +#define DT_CONST_NPROBES 26 #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 29cfbd84..1dc119ea 100644 --- a/libdtrace/dt_cc.c +++ b/libdtrace/dt_cc.c @@ -1082,7 +1082,8 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, case DT_CONST_TASK_PID: case DT_CONST_TASK_TGID: case DT_CONST_TASK_REAL_PARENT: - case DT_CONST_TASK_COMM: { + case DT_CONST_TASK_COMM: + case DT_CONST_TASK_MM: { ctf_file_t *cfp = dtp->dt_shared_ctf; ctf_id_t type; ctf_membinfo_t ctm; @@ -1108,6 +1109,36 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, case DT_CONST_TASK_COMM: rc = ctf_member_info(cfp, type, "comm", &ctm); break; + case DT_CONST_TASK_MM: + rc = ctf_member_info(cfp, type, "mm", &ctm); + break; + } + if (rc == CTF_ERR) + goto err_ctf; + nrp->dofr_data = ctm.ctm_offset / NBBY; + continue; + } + case DT_CONST_TASK_MM_ARG_START: + case DT_CONST_TASK_MM_ARG_END: { + ctf_file_t *cfp = dtp->dt_shared_ctf; + ctf_id_t type; + ctf_membinfo_t ctm; + int rc = 0; + + if (!cfp) + return dt_set_errno(dtp, EDT_NOCTF); + + type = ctf_lookup_by_name(cfp, "struct mm_struct"); + if (type == CTF_ERR) + goto err_ctf; + + switch (idp->di_id) { + case DT_CONST_TASK_MM_ARG_START: + rc = ctf_member_info(cfp, type, "arg_start", &ctm); + break; + case DT_CONST_TASK_MM_ARG_END: + rc = ctf_member_info(cfp, type, "arg_end", &ctm); + break; } if (rc == CTF_ERR) goto err_ctf; diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index b48e27f0..5268e900 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -3341,7 +3341,6 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) } /* built-in variables (note: args[] is handled in dt_cg_array_op) */ - /* Special case for arg0 through arg9; encode as args[n] */ if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); idx = idp->di_id - DIF_VAR_ARG0; @@ -3351,6 +3350,31 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) idp->di_id == DIF_VAR_PROBENAME) { fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_probedesc"); idx = idp->di_id; + } else if (idp->di_id == DIF_VAR_EXECARGS) { + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_execargs"); + assert(fnp != NULL); + + if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + + dt_cg_tstring_alloc(yypcb, dnp); + + if (dt_regset_xalloc_args(drp) == -1) + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + + dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_2, BPF_REG_1, DCTX_MEM)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, dnp->dn_tstring->dn_value)); + dt_regset_xalloc(drp, BPF_REG_0); + emite(dlp, BPF_CALL_FUNC(fnp->di_id), fnp); + dt_regset_free_args(drp); + + dt_cg_check_fault(yypcb); + + emit(dlp, BPF_MOV_REG(dnp->dn_reg, BPF_REG_0)); + dt_regset_free(drp, BPF_REG_0); + + return; } else { char *fn; diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c index 07d22afd..9ad4f5e7 100644 --- a/libdtrace/dt_dlibs.c +++ b/libdtrace/dt_dlibs.c @@ -89,6 +89,9 @@ static const dt_ident_t dt_bpf_symbols[] = { DT_BPF_SYMBOL_ID(TASK_TGID, DT_IDENT_SCALAR, DT_CONST_TASK_TGID), DT_BPF_SYMBOL_ID(TASK_REAL_PARENT, DT_IDENT_SCALAR, DT_CONST_TASK_REAL_PARENT), DT_BPF_SYMBOL_ID(TASK_COMM, DT_IDENT_SCALAR, DT_CONST_TASK_COMM), + DT_BPF_SYMBOL_ID(TASK_MM, DT_IDENT_SCALAR, DT_CONST_TASK_MM), + DT_BPF_SYMBOL_ID(TASK_MM_ARG_START, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_START), + DT_BPF_SYMBOL_ID(TASK_MM_ARG_END, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_END), DT_BPF_SYMBOL_ID(MUTEX_OWNER, DT_IDENT_SCALAR, DT_CONST_MUTEX_OWNER), DT_BPF_SYMBOL_ID(RWLOCK_CNTS, DT_IDENT_SCALAR, DT_CONST_RWLOCK_CNTS), DT_BPF_SYMBOL_ID(DCTX_RODATA, DT_IDENT_SCALAR, DT_CONST_DCTX_RODATA), diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c index a0205887..51c056b2 100644 --- a/libdtrace/dt_open.c +++ b/libdtrace/dt_open.c @@ -153,6 +153,8 @@ static const dt_ident_t _dtrace_globals[] = { &dt_idops_type, "uint64_t" }, { "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int" }, +{ "execargs", DT_IDENT_SCALAR, 0, DIF_VAR_EXECARGS, + DT_ATTR_STABCMN, DT_VERS_2_0, &dt_idops_type, "string" }, { "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "exit", DT_IDENT_ACTFUNC, 0, DT_ACT_EXIT, DT_ATTR_STABCMN, DT_VERS_1_0, diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in index 038cf69b..adcb1889 100644 --- a/libdtrace/procfs.d.in +++ b/libdtrace/procfs.d.in @@ -179,9 +179,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/test/unittest/builtinvar/tst.psinfo-bug21974606.d b/test/unittest/builtinvar/tst.psinfo-bug21974606.d index 68d9503d..67fea54e 100644 --- a/test/unittest/builtinvar/tst.psinfo-bug21974606.d +++ b/test/unittest/builtinvar/tst.psinfo-bug21974606.d @@ -4,11 +4,9 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* - * ASSERTION: - * To ensure pr_psargs does not have an (extra) trailing space. + * ASSERTION: To ensure pr_psargs does not have an (extra) trailing space. * * SECTION: Variables/Built-in Variables */ diff --git a/test/unittest/builtinvar/tst.psinfo-bug22561297.d b/test/unittest/builtinvar/tst.psinfo-bug22561297.d index b9efd0ec..5a9fe333 100644 --- a/test/unittest/builtinvar/tst.psinfo-bug22561297.d +++ b/test/unittest/builtinvar/tst.psinfo-bug22561297.d @@ -4,11 +4,9 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* - * ASSERTION: - * To print psinfo structure values from profile. + * ASSERTION: To print psinfo structure values from profile. * * SECTION: Variables/Built-in Variables */ @@ -32,12 +30,14 @@ tick-10ms printf("address of process = %p\n", curpsinfo->pr_addr); printf("address of controlling tty = %p\n", curpsinfo->pr_ttydev); printf("process name = %s\n", curpsinfo->pr_fname); - /* These are still getting faked */ printf("initial chars of arg list = %s\n", curpsinfo->pr_psargs); printf("wait status for zombie = %d\n", curpsinfo->pr_wstat); +/* + * These are not implemented yet. printf("initial argument count = %d\n", curpsinfo->pr_argc); printf("initial argument vector = %p\n", curpsinfo->pr_argv); printf("initial environment vector = %p\n", curpsinfo->pr_envp); + */ printf("process data model = %d\n", curpsinfo->pr_dmodel); printf("task id = %d\n", curpsinfo->pr_taskid); printf("project id = %d\n", curpsinfo->pr_projid); diff --git a/test/unittest/builtinvar/tst.psinfo.d b/test/unittest/builtinvar/tst.psinfo.d index 92f91de7..09bcce86 100644 --- a/test/unittest/builtinvar/tst.psinfo.d +++ b/test/unittest/builtinvar/tst.psinfo.d @@ -4,11 +4,9 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* - * ASSERTION: - * To print psinfo structure values from profile. + * ASSERTION: To print psinfo structure values from profile. * * SECTION: Variables/Built-in Variables */ @@ -31,12 +29,14 @@ tick-10ms printf("address of process = %p\n", curpsinfo->pr_addr); printf("address of controlling tty = %p\n", curpsinfo->pr_ttydev); printf("process name = %s\n", curpsinfo->pr_fname); - /* These are still getting faked */ printf("initial chars of arg list = %s\n", curpsinfo->pr_psargs); printf("wait status for zombie = %d\n", curpsinfo->pr_wstat); +/* + * These are not implemented yet. printf("initial argument count = %d\n", curpsinfo->pr_argc); printf("initial argument vector = %p\n", curpsinfo->pr_argv); printf("initial environment vector = %p\n", curpsinfo->pr_envp); + */ printf("process data model = %d\n", curpsinfo->pr_dmodel); printf("task id = %d\n", curpsinfo->pr_taskid); printf("project id = %d\n", curpsinfo->pr_projid); diff --git a/test/unittest/builtinvar/tst.psinfo1.d b/test/unittest/builtinvar/tst.psinfo1.d index 9e6d5053..be9e251c 100644 --- a/test/unittest/builtinvar/tst.psinfo1.d +++ b/test/unittest/builtinvar/tst.psinfo1.d @@ -4,11 +4,9 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* - * ASSERTION: - * To print psinfo structure values. + * ASSERTION: To print psinfo structure values. * * SECTION: Variables/Built-in Variables */ @@ -29,12 +27,14 @@ BEGIN printf("address of process = %p\n", curpsinfo->pr_addr); printf("address of controlling tty = %p\n", curpsinfo->pr_ttydev); printf("process name = %s\n", curpsinfo->pr_fname); - /* These are still getting faked */ printf("initial chars of arg list = %s\n", curpsinfo->pr_psargs); printf("wait status for zombie = %d\n", curpsinfo->pr_wstat); +/* + * These are not implemented yet. printf("initial argument count = %d\n", curpsinfo->pr_argc); printf("initial argument vector = %p\n", curpsinfo->pr_argv); printf("initial environment vector = %p\n", curpsinfo->pr_envp); + */ printf("process data model = %d\n", curpsinfo->pr_dmodel); printf("task id = %d\n", curpsinfo->pr_taskid); printf("project id = %d\n", curpsinfo->pr_projid); diff --git a/test/unittest/proc/tst.pr_psargs.d b/test/unittest/proc/tst.pr_psargs.d new file mode 100644 index 00000000..5c4995ad --- /dev/null +++ b/test/unittest/proc/tst.pr_psargs.d @@ -0,0 +1,36 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: psinfo->pr_psargs provides correct results. + */ + +#pragma D option destructive +#pragma D option quiet + +BEGIN +{ + mypid = pid; + system("/bin/echo TEST a b c "); +} + +proc:::exec-success +/progenyof(mypid) && curpsinfo->pr_psargs == "/bin/echo TEST a b c"/ +{ + trace(curpsinfo->pr_psargs); + exit(0); +} + +tick-1s +{ + exit(1); +} + +ERROR +{ + exit(1); +} diff --git a/test/unittest/proc/tst.pr_psargs.r b/test/unittest/proc/tst.pr_psargs.r new file mode 100644 index 00000000..bbfe6074 --- /dev/null +++ b/test/unittest/proc/tst.pr_psargs.r @@ -0,0 +1,2 @@ +TEST a b c +/bin/echo TEST a b c diff --git a/test/unittest/proc/tst.pr_psargs_other_task.d b/test/unittest/proc/tst.pr_psargs_other_task.d new file mode 100644 index 00000000..040a7864 --- /dev/null +++ b/test/unittest/proc/tst.pr_psargs_other_task.d @@ -0,0 +1,37 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: psinfo->pr_psargs is only implemented for curthread + */ + +#pragma D option destructive +#pragma D option quiet + +BEGIN +{ + mypid = pid; + tsk = curthread; + system("/bin/echo TEST a b c "); +} + +proc:::exec-success +/progenyof(mypid) && curpsinfo->pr_psargs == "/bin/echo TEST a b c"/ +{ + trace(xlate < psinfo_t > (tsk).pr_psargs); + exit(0); +} + +tick-1s +{ + exit(1); +} + +ERROR +{ + exit(1); +} diff --git a/test/unittest/proc/tst.pr_psargs_other_task.r b/test/unittest/proc/tst.pr_psargs_other_task.r new file mode 100644 index 00000000..ed0aafb2 --- /dev/null +++ b/test/unittest/proc/tst.pr_psargs_other_task.r @@ -0,0 +1,9 @@ +TEST a b c + + 0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef + 0: 3c 75 6e 6b 6e 6f 77 6e 3e 00 00 00 00 00 00 00 ....... + 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + diff --git a/test/unittest/variables/bvar/tst.execargs.d b/test/unittest/variables/bvar/tst.execargs.d new file mode 100644 index 00000000..d4eac223 --- /dev/null +++ b/test/unittest/variables/bvar/tst.execargs.d @@ -0,0 +1,23 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: The 'execargs' variable value can be retrieved. + * + * SECTION: Variables/Built-in Variables/execargs + */ + +#pragma D option quiet + +BEGIN { + trace(execargs); + exit(0); +} + +ERROR { + exit(1); +} -- 2.45.2 From kris.van.hees at oracle.com Fri Jan 24 07:17:54 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Fri, 24 Jan 2025 02:17:54 -0500 Subject: [DTrace-devel] [PATCH v4] procfs: implement execargs for pr_psargs translator support Message-ID: <4ba6cc25930511a2786d92a629edc0ea.kris.van.hees@oracle.com> Implement a new execargs built-in variable to provide the ps-style argument string for the current task. It is used in the psinfo translator for the pr_psargs member. Due to BPF limitations, it is only possible to retrieve this information for the current task. The data is stored in the task's address space, and the only BPF helper that can access data in another task's address space is not allowed to be used in non-sleepable programs (such as tracing programs). Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh --- bpf/Build | 1 + bpf/bvar_execargs.S | 97 +++++++++++++++++++ dlibs/aarch64/5.11/procfs.d | 4 +- dlibs/aarch64/5.12/procfs.d | 4 +- dlibs/aarch64/5.14/procfs.d | 4 +- dlibs/aarch64/5.16/procfs.d | 4 +- dlibs/aarch64/5.2/procfs.d | 4 +- dlibs/aarch64/5.6/procfs.d | 4 +- dlibs/aarch64/6.1/procfs.d | 4 +- dlibs/aarch64/6.10/procfs.d | 4 +- dlibs/x86_64/5.11/procfs.d | 5 +- dlibs/x86_64/5.12/procfs.d | 5 +- dlibs/x86_64/5.14/procfs.d | 5 +- dlibs/x86_64/5.16/procfs.d | 5 +- dlibs/x86_64/5.2/procfs.d | 5 +- dlibs/x86_64/5.6/procfs.d | 5 +- dlibs/x86_64/6.1/procfs.d | 5 +- dlibs/x86_64/6.10/procfs.d | 5 +- include/dtrace/dif_defines.h | 1 + libdtrace/dt_bpf.h | 21 ++-- libdtrace/dt_cc.c | 33 ++++++- libdtrace/dt_cg.c | 26 ++++- libdtrace/dt_dlibs.c | 3 + libdtrace/dt_open.c | 2 + libdtrace/procfs.d.in | 5 +- .../builtinvar/tst.psinfo-bug21974606.d | 4 +- .../builtinvar/tst.psinfo-bug22561297.d | 8 +- test/unittest/builtinvar/tst.psinfo.d | 8 +- test/unittest/builtinvar/tst.psinfo1.d | 8 +- test/unittest/proc/tst.pr_psargs.d | 36 +++++++ test/unittest/proc/tst.pr_psargs.r | 2 + test/unittest/proc/tst.pr_psargs_other_task.d | 37 +++++++ test/unittest/proc/tst.pr_psargs_other_task.r | 2 + test/unittest/variables/bvar/tst.execargs.d | 23 +++++ 34 files changed, 312 insertions(+), 77 deletions(-) create mode 100644 bpf/bvar_execargs.S create mode 100644 test/unittest/proc/tst.pr_psargs.d create mode 100644 test/unittest/proc/tst.pr_psargs.r create mode 100644 test/unittest/proc/tst.pr_psargs_other_task.d create mode 100644 test/unittest/proc/tst.pr_psargs_other_task.r create mode 100644 test/unittest/variables/bvar/tst.execargs.d diff --git a/bpf/Build b/bpf/Build index 3e43f4b6..a9fb100a 100644 --- a/bpf/Build +++ b/bpf/Build @@ -23,6 +23,7 @@ bpf_dlib_SRCDEPS = $(objdir)/include/.dir.stamp $(objdir)/include/bpf_asm_helper bpf_dlib_SOURCES = \ agg_lqbin.c agg_qbin.c \ basename.S \ + bvar_execargs.S \ cleanpath.S \ dirname.S \ get_agg.c \ diff --git a/bpf/bvar_execargs.S b/bpf/bvar_execargs.S new file mode 100644 index 00000000..1c47cafb --- /dev/null +++ b/bpf/bvar_execargs.S @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025, Oracle and/or its affiliates. + */ + +#include +#include + +/* + * uint64_t dt_bvar_execargs(const dt_dctx_t *dctx, char *args) + */ + .text + .align 4 + .global dt_bvar_execargs + .type dt_bvar_execargs, @function +dt_bvar_execargs: + stxdw [%fp+-8], %r1 /* save dctx to stack */ + mov %r9, %r2 /* %r9 = args */ + + mov %r6, 0 /* set %r6 in case of error */ + call BPF_FUNC_get_current_task /* get curthread (T) */ + jeq %r0, 0, .Lerror + + mov %r6, %r0 + add %r6, TASK_MM /* %r6 = &(T->mm) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r8, [%r9+0] /* %r8 = T->mm */ + jeq %r8, 0, .Lempty + mov %r6, %r8 + add %r6, TASK_MM_ARG_START /* ptr = &(T->mm->arg_start) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r7, [%r9+0] /* %r7 = T->mm->arg_start */ + mov %r6, %r8 + add %r6, TASK_MM_ARG_END /* ptr = &(T->mm->arg_end) */ + + mov %r1, %r9 + mov %r2, 8 + mov %r3, %r6 + call BPF_FUNC_probe_read + jne %r0, 0, .Lerror + + ldxdw %r6, [%r9+0] /* %r6 = T->mm->arg_end */ + + mov %r8, %r6 + sub %r8, %r7 /* %r8 = len = arg_end - arg_start */ + jslt %r8, 2, .Lempty + mov %r0, STRSZ + jslt %r8, %r0, .Llen_ok + mov %r8, %r0 +.Llen_ok: + + /* read data from arg_start to arg_end */ + mov %r1, %r9 + mov %r2, %r8 + mov %r3, %r7 + call BPF_FUNC_probe_read /* bpf_probe_read(&args, len + 1, arg_start) */ + jne %r0, 0, .Lerror + + /* loop over args and replace '\0' with ' ' */ + mov %r1, %r8 + sub %r1, 2 +.Lloop: + mov %r2, %r9 + add %r2, %r1 + ldxb %r0, [%r2+0] + jne %r0, 0, .Lnot_nil + stb [%r2+0], 32 +.Lnot_nil: + sub %r1, 1 + jsge %r1, 0, .Lloop + +.Ldone: + mov %r0, %r9 + exit /* return args */ +.Lerror: + ldxdw %r1, [%fp+-8] + mov %r2, PC + mov %r3, DTRACEFLT_BADADDR + mov %r4, %r6 + call dt_probe_error +.Lempty: + mov %r0, %r9 + stb [%r9+0], 0 /* args[0] = 0 */ + exit /* return args */ + .size dt_bvar_execargs, .-dt_bvar_execargs diff --git a/dlibs/aarch64/5.11/procfs.d b/dlibs/aarch64/5.11/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.11/procfs.d +++ b/dlibs/aarch64/5.11/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.12/procfs.d b/dlibs/aarch64/5.12/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.12/procfs.d +++ b/dlibs/aarch64/5.12/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.14/procfs.d b/dlibs/aarch64/5.14/procfs.d index 584ac325..ef27bb70 100644 --- a/dlibs/aarch64/5.14/procfs.d +++ b/dlibs/aarch64/5.14/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.16/procfs.d b/dlibs/aarch64/5.16/procfs.d index 5aabc6f1..cad2d2c5 100644 --- a/dlibs/aarch64/5.16/procfs.d +++ b/dlibs/aarch64/5.16/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.2/procfs.d b/dlibs/aarch64/5.2/procfs.d index 683ff5a8..6b1b1b9c 100644 --- a/dlibs/aarch64/5.2/procfs.d +++ b/dlibs/aarch64/5.2/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/5.6/procfs.d b/dlibs/aarch64/5.6/procfs.d index 44ec4280..70a43ddf 100644 --- a/dlibs/aarch64/5.6/procfs.d +++ b/dlibs/aarch64/5.6/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/6.1/procfs.d b/dlibs/aarch64/6.1/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/aarch64/6.1/procfs.d +++ b/dlibs/aarch64/6.1/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/aarch64/6.10/procfs.d b/dlibs/aarch64/6.10/procfs.d index 5d7873b5..4cb7b77c 100644 --- a/dlibs/aarch64/6.10/procfs.d +++ b/dlibs/aarch64/6.10/procfs.d @@ -141,9 +141,7 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = d_execargs(T); pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.11/procfs.d b/dlibs/x86_64/5.11/procfs.d index 7274554e..f0071440 100644 --- a/dlibs/x86_64/5.11/procfs.d +++ b/dlibs/x86_64/5.11/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.12/procfs.d b/dlibs/x86_64/5.12/procfs.d index 7274554e..f0071440 100644 --- a/dlibs/x86_64/5.12/procfs.d +++ b/dlibs/x86_64/5.12/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.14/procfs.d b/dlibs/x86_64/5.14/procfs.d index d1cf90d3..17f95e5c 100644 --- a/dlibs/x86_64/5.14/procfs.d +++ b/dlibs/x86_64/5.14/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.16/procfs.d b/dlibs/x86_64/5.16/procfs.d index 5aabc6f1..f924c2a1 100644 --- a/dlibs/x86_64/5.16/procfs.d +++ b/dlibs/x86_64/5.16/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.2/procfs.d b/dlibs/x86_64/5.2/procfs.d index 35538862..36608ad0 100644 --- a/dlibs/x86_64/5.2/procfs.d +++ b/dlibs/x86_64/5.2/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/5.6/procfs.d b/dlibs/x86_64/5.6/procfs.d index 7274554e..f0071440 100644 --- a/dlibs/x86_64/5.6/procfs.d +++ b/dlibs/x86_64/5.6/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/6.1/procfs.d b/dlibs/x86_64/6.1/procfs.d index 5d7873b5..a3d7f949 100644 --- a/dlibs/x86_64/6.1/procfs.d +++ b/dlibs/x86_64/6.1/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/dlibs/x86_64/6.10/procfs.d b/dlibs/x86_64/6.10/procfs.d index 5d7873b5..a3d7f949 100644 --- a/dlibs/x86_64/6.10/procfs.d +++ b/dlibs/x86_64/6.10/procfs.d @@ -141,9 +141,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/include/dtrace/dif_defines.h b/include/dtrace/dif_defines.h index c8c1d961..9f6e3b55 100644 --- a/include/dtrace/dif_defines.h +++ b/include/dtrace/dif_defines.h @@ -162,6 +162,7 @@ #define DIF_VAR_GID 0x011f #define DIF_VAR_ERRNO 0x0120 #define DIF_VAR_CURCPU 0x0121 +#define DIF_VAR_EXECARGS 0x0122 #define DIF_SUBR_RAND 0 #define DIF_SUBR_MUTEX_OWNED 1 diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h index 6518de66..85934d2d 100644 --- a/libdtrace/dt_bpf.h +++ b/libdtrace/dt_bpf.h @@ -47,15 +47,18 @@ extern "C" { #define DT_CONST_TASK_TGID 12 #define DT_CONST_TASK_REAL_PARENT 13 #define DT_CONST_TASK_COMM 14 -#define DT_CONST_MUTEX_OWNER 15 -#define DT_CONST_RWLOCK_CNTS 16 -#define DT_CONST_DCTX_RODATA 17 -#define DT_CONST_RODATA_OFF 18 -#define DT_CONST_RODATA_SIZE 19 -#define DT_CONST_ZERO_OFF 20 -#define DT_CONST_STACK_OFF 21 -#define DT_CONST_STACK_SKIP 22 -#define DT_CONST_NPROBES 23 +#define DT_CONST_TASK_MM 15 +#define DT_CONST_TASK_MM_ARG_START 16 +#define DT_CONST_TASK_MM_ARG_END 17 +#define DT_CONST_MUTEX_OWNER 18 +#define DT_CONST_RWLOCK_CNTS 19 +#define DT_CONST_DCTX_RODATA 20 +#define DT_CONST_RODATA_OFF 21 +#define DT_CONST_RODATA_SIZE 22 +#define DT_CONST_ZERO_OFF 23 +#define DT_CONST_STACK_OFF 24 +#define DT_CONST_STACK_SKIP 25 +#define DT_CONST_NPROBES 26 #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 29cfbd84..1dc119ea 100644 --- a/libdtrace/dt_cc.c +++ b/libdtrace/dt_cc.c @@ -1082,7 +1082,8 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, case DT_CONST_TASK_PID: case DT_CONST_TASK_TGID: case DT_CONST_TASK_REAL_PARENT: - case DT_CONST_TASK_COMM: { + case DT_CONST_TASK_COMM: + case DT_CONST_TASK_MM: { ctf_file_t *cfp = dtp->dt_shared_ctf; ctf_id_t type; ctf_membinfo_t ctm; @@ -1108,6 +1109,36 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp, case DT_CONST_TASK_COMM: rc = ctf_member_info(cfp, type, "comm", &ctm); break; + case DT_CONST_TASK_MM: + rc = ctf_member_info(cfp, type, "mm", &ctm); + break; + } + if (rc == CTF_ERR) + goto err_ctf; + nrp->dofr_data = ctm.ctm_offset / NBBY; + continue; + } + case DT_CONST_TASK_MM_ARG_START: + case DT_CONST_TASK_MM_ARG_END: { + ctf_file_t *cfp = dtp->dt_shared_ctf; + ctf_id_t type; + ctf_membinfo_t ctm; + int rc = 0; + + if (!cfp) + return dt_set_errno(dtp, EDT_NOCTF); + + type = ctf_lookup_by_name(cfp, "struct mm_struct"); + if (type == CTF_ERR) + goto err_ctf; + + switch (idp->di_id) { + case DT_CONST_TASK_MM_ARG_START: + rc = ctf_member_info(cfp, type, "arg_start", &ctm); + break; + case DT_CONST_TASK_MM_ARG_END: + rc = ctf_member_info(cfp, type, "arg_end", &ctm); + break; } if (rc == CTF_ERR) goto err_ctf; diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index b48e27f0..5268e900 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -3341,7 +3341,6 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) } /* built-in variables (note: args[] is handled in dt_cg_array_op) */ - /* Special case for arg0 through arg9; encode as args[n] */ if (idp->di_id >= DIF_VAR_ARG0 && idp->di_id <= DIF_VAR_ARG9) { fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_args"); idx = idp->di_id - DIF_VAR_ARG0; @@ -3351,6 +3350,31 @@ dt_cg_load_var(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp) idp->di_id == DIF_VAR_PROBENAME) { fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_probedesc"); idx = idp->di_id; + } else if (idp->di_id == DIF_VAR_EXECARGS) { + fnp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_bvar_execargs"); + assert(fnp != NULL); + + if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1) + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + + dt_cg_tstring_alloc(yypcb, dnp); + + if (dt_regset_xalloc_args(drp) == -1) + longjmp(yypcb->pcb_jmpbuf, EDT_NOREG); + + dt_cg_access_dctx(BPF_REG_1, dlp, drp, -1); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_2, BPF_REG_1, DCTX_MEM)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, dnp->dn_tstring->dn_value)); + dt_regset_xalloc(drp, BPF_REG_0); + emite(dlp, BPF_CALL_FUNC(fnp->di_id), fnp); + dt_regset_free_args(drp); + + dt_cg_check_fault(yypcb); + + emit(dlp, BPF_MOV_REG(dnp->dn_reg, BPF_REG_0)); + dt_regset_free(drp, BPF_REG_0); + + return; } else { char *fn; diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c index 07d22afd..9ad4f5e7 100644 --- a/libdtrace/dt_dlibs.c +++ b/libdtrace/dt_dlibs.c @@ -89,6 +89,9 @@ static const dt_ident_t dt_bpf_symbols[] = { DT_BPF_SYMBOL_ID(TASK_TGID, DT_IDENT_SCALAR, DT_CONST_TASK_TGID), DT_BPF_SYMBOL_ID(TASK_REAL_PARENT, DT_IDENT_SCALAR, DT_CONST_TASK_REAL_PARENT), DT_BPF_SYMBOL_ID(TASK_COMM, DT_IDENT_SCALAR, DT_CONST_TASK_COMM), + DT_BPF_SYMBOL_ID(TASK_MM, DT_IDENT_SCALAR, DT_CONST_TASK_MM), + DT_BPF_SYMBOL_ID(TASK_MM_ARG_START, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_START), + DT_BPF_SYMBOL_ID(TASK_MM_ARG_END, DT_IDENT_SCALAR, DT_CONST_TASK_MM_ARG_END), DT_BPF_SYMBOL_ID(MUTEX_OWNER, DT_IDENT_SCALAR, DT_CONST_MUTEX_OWNER), DT_BPF_SYMBOL_ID(RWLOCK_CNTS, DT_IDENT_SCALAR, DT_CONST_RWLOCK_CNTS), DT_BPF_SYMBOL_ID(DCTX_RODATA, DT_IDENT_SCALAR, DT_CONST_DCTX_RODATA), diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c index a0205887..51c056b2 100644 --- a/libdtrace/dt_open.c +++ b/libdtrace/dt_open.c @@ -153,6 +153,8 @@ static const dt_ident_t _dtrace_globals[] = { &dt_idops_type, "uint64_t" }, { "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int" }, +{ "execargs", DT_IDENT_SCALAR, 0, DIF_VAR_EXECARGS, + DT_ATTR_STABCMN, DT_VERS_2_0, &dt_idops_type, "string" }, { "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "exit", DT_IDENT_ACTFUNC, 0, DT_ACT_EXIT, DT_ATTR_STABCMN, DT_VERS_1_0, diff --git a/libdtrace/procfs.d.in b/libdtrace/procfs.d.in index 038cf69b..adcb1889 100644 --- a/libdtrace/procfs.d.in +++ b/libdtrace/procfs.d.in @@ -179,9 +179,8 @@ translator psinfo_t < struct task_struct *T > { : (struct tty_struct *)-1; pr_fname = T->comm; -/* - pr_psargs = stringof(get_psinfo(T)->__psinfo(psargs)); - */ + pr_psargs = T == curthread ? execargs + : ""; pr_wstat = 0; /* pr_argc = get_psinfo(T)->__psinfo(argc); diff --git a/test/unittest/builtinvar/tst.psinfo-bug21974606.d b/test/unittest/builtinvar/tst.psinfo-bug21974606.d index 68d9503d..67fea54e 100644 --- a/test/unittest/builtinvar/tst.psinfo-bug21974606.d +++ b/test/unittest/builtinvar/tst.psinfo-bug21974606.d @@ -4,11 +4,9 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* - * ASSERTION: - * To ensure pr_psargs does not have an (extra) trailing space. + * ASSERTION: To ensure pr_psargs does not have an (extra) trailing space. * * SECTION: Variables/Built-in Variables */ diff --git a/test/unittest/builtinvar/tst.psinfo-bug22561297.d b/test/unittest/builtinvar/tst.psinfo-bug22561297.d index b9efd0ec..5a9fe333 100644 --- a/test/unittest/builtinvar/tst.psinfo-bug22561297.d +++ b/test/unittest/builtinvar/tst.psinfo-bug22561297.d @@ -4,11 +4,9 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* - * ASSERTION: - * To print psinfo structure values from profile. + * ASSERTION: To print psinfo structure values from profile. * * SECTION: Variables/Built-in Variables */ @@ -32,12 +30,14 @@ tick-10ms printf("address of process = %p\n", curpsinfo->pr_addr); printf("address of controlling tty = %p\n", curpsinfo->pr_ttydev); printf("process name = %s\n", curpsinfo->pr_fname); - /* These are still getting faked */ printf("initial chars of arg list = %s\n", curpsinfo->pr_psargs); printf("wait status for zombie = %d\n", curpsinfo->pr_wstat); +/* + * These are not implemented yet. printf("initial argument count = %d\n", curpsinfo->pr_argc); printf("initial argument vector = %p\n", curpsinfo->pr_argv); printf("initial environment vector = %p\n", curpsinfo->pr_envp); + */ printf("process data model = %d\n", curpsinfo->pr_dmodel); printf("task id = %d\n", curpsinfo->pr_taskid); printf("project id = %d\n", curpsinfo->pr_projid); diff --git a/test/unittest/builtinvar/tst.psinfo.d b/test/unittest/builtinvar/tst.psinfo.d index 92f91de7..09bcce86 100644 --- a/test/unittest/builtinvar/tst.psinfo.d +++ b/test/unittest/builtinvar/tst.psinfo.d @@ -4,11 +4,9 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* - * ASSERTION: - * To print psinfo structure values from profile. + * ASSERTION: To print psinfo structure values from profile. * * SECTION: Variables/Built-in Variables */ @@ -31,12 +29,14 @@ tick-10ms printf("address of process = %p\n", curpsinfo->pr_addr); printf("address of controlling tty = %p\n", curpsinfo->pr_ttydev); printf("process name = %s\n", curpsinfo->pr_fname); - /* These are still getting faked */ printf("initial chars of arg list = %s\n", curpsinfo->pr_psargs); printf("wait status for zombie = %d\n", curpsinfo->pr_wstat); +/* + * These are not implemented yet. printf("initial argument count = %d\n", curpsinfo->pr_argc); printf("initial argument vector = %p\n", curpsinfo->pr_argv); printf("initial environment vector = %p\n", curpsinfo->pr_envp); + */ printf("process data model = %d\n", curpsinfo->pr_dmodel); printf("task id = %d\n", curpsinfo->pr_taskid); printf("project id = %d\n", curpsinfo->pr_projid); diff --git a/test/unittest/builtinvar/tst.psinfo1.d b/test/unittest/builtinvar/tst.psinfo1.d index 9e6d5053..be9e251c 100644 --- a/test/unittest/builtinvar/tst.psinfo1.d +++ b/test/unittest/builtinvar/tst.psinfo1.d @@ -4,11 +4,9 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@xfail: dtv2 */ /* - * ASSERTION: - * To print psinfo structure values. + * ASSERTION: To print psinfo structure values. * * SECTION: Variables/Built-in Variables */ @@ -29,12 +27,14 @@ BEGIN printf("address of process = %p\n", curpsinfo->pr_addr); printf("address of controlling tty = %p\n", curpsinfo->pr_ttydev); printf("process name = %s\n", curpsinfo->pr_fname); - /* These are still getting faked */ printf("initial chars of arg list = %s\n", curpsinfo->pr_psargs); printf("wait status for zombie = %d\n", curpsinfo->pr_wstat); +/* + * These are not implemented yet. printf("initial argument count = %d\n", curpsinfo->pr_argc); printf("initial argument vector = %p\n", curpsinfo->pr_argv); printf("initial environment vector = %p\n", curpsinfo->pr_envp); + */ printf("process data model = %d\n", curpsinfo->pr_dmodel); printf("task id = %d\n", curpsinfo->pr_taskid); printf("project id = %d\n", curpsinfo->pr_projid); diff --git a/test/unittest/proc/tst.pr_psargs.d b/test/unittest/proc/tst.pr_psargs.d new file mode 100644 index 00000000..5c4995ad --- /dev/null +++ b/test/unittest/proc/tst.pr_psargs.d @@ -0,0 +1,36 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: psinfo->pr_psargs provides correct results. + */ + +#pragma D option destructive +#pragma D option quiet + +BEGIN +{ + mypid = pid; + system("/bin/echo TEST a b c "); +} + +proc:::exec-success +/progenyof(mypid) && curpsinfo->pr_psargs == "/bin/echo TEST a b c"/ +{ + trace(curpsinfo->pr_psargs); + exit(0); +} + +tick-1s +{ + exit(1); +} + +ERROR +{ + exit(1); +} diff --git a/test/unittest/proc/tst.pr_psargs.r b/test/unittest/proc/tst.pr_psargs.r new file mode 100644 index 00000000..bbfe6074 --- /dev/null +++ b/test/unittest/proc/tst.pr_psargs.r @@ -0,0 +1,2 @@ +TEST a b c +/bin/echo TEST a b c diff --git a/test/unittest/proc/tst.pr_psargs_other_task.d b/test/unittest/proc/tst.pr_psargs_other_task.d new file mode 100644 index 00000000..040a7864 --- /dev/null +++ b/test/unittest/proc/tst.pr_psargs_other_task.d @@ -0,0 +1,37 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: psinfo->pr_psargs is only implemented for curthread + */ + +#pragma D option destructive +#pragma D option quiet + +BEGIN +{ + mypid = pid; + tsk = curthread; + system("/bin/echo TEST a b c "); +} + +proc:::exec-success +/progenyof(mypid) && curpsinfo->pr_psargs == "/bin/echo TEST a b c"/ +{ + trace(xlate < psinfo_t > (tsk).pr_psargs); + exit(0); +} + +tick-1s +{ + exit(1); +} + +ERROR +{ + exit(1); +} diff --git a/test/unittest/proc/tst.pr_psargs_other_task.r b/test/unittest/proc/tst.pr_psargs_other_task.r new file mode 100644 index 00000000..6e3f5ebf --- /dev/null +++ b/test/unittest/proc/tst.pr_psargs_other_task.r @@ -0,0 +1,2 @@ +TEST a b c + diff --git a/test/unittest/variables/bvar/tst.execargs.d b/test/unittest/variables/bvar/tst.execargs.d new file mode 100644 index 00000000..d4eac223 --- /dev/null +++ b/test/unittest/variables/bvar/tst.execargs.d @@ -0,0 +1,23 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2025, 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. + */ + +/* + * ASSERTION: The 'execargs' variable value can be retrieved. + * + * SECTION: Variables/Built-in Variables/execargs + */ + +#pragma D option quiet + +BEGIN { + trace(execargs); + exit(0); +} + +ERROR { + exit(1); +} -- 2.45.2