From noreply at github.com Sun Jun 1 16:54:48 2025 From: noreply at github.com (Kris Van Hees) Date: Sun, 01 Jun 2025 09:54:48 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] 315e78: ADD TO link PATCH Message-ID: Branch: refs/heads/kvh/usdt-dev Home: https://github.com/oracle/dtrace-utils Commit: 315e789d37be1268ac3041d8d762267db2d9cffc https://github.com/oracle/dtrace-utils/commit/315e789d37be1268ac3041d8d762267db2d9cffc Author: Kris Van Hees Date: 2025-05-31 (Sat, 31 May 2025) Changed paths: M libdtrace/dt_prov_uprobe.c Log Message: ----------- ADD TO link PATCH Signed-off-by: Kris Van Hees Commit: 563e00898cfb8885f344b8c0f2681abc2afa3dba https://github.com/oracle/dtrace-utils/commit/563e00898cfb8885f344b8c0f2681abc2afa3dba Author: Kris Van Hees Date: 2025-05-31 (Sat, 31 May 2025) Changed paths: M dtprobed/dtprobed.c Log Message: ----------- ADD TO dtprobed PATCH Signed-off-by: Kris Van Hees Commit: 9feef75f8920f8f05839a267a91a15c47aa8eded https://github.com/oracle/dtrace-utils/commit/9feef75f8920f8f05839a267a91a15c47aa8eded Author: Kris Van Hees Date: 2025-05-31 (Sat, 31 May 2025) Changed paths: M libcommon/usdt_parser_notes.c Log Message: ----------- ADD TO notes PATCH Signed-off-by: Kris Van Hees Commit: 755e1ee438ea68914eba73fca7b2ae2ecfbe8da6 https://github.com/oracle/dtrace-utils/commit/755e1ee438ea68914eba73fca7b2ae2ecfbe8da6 Author: Kris Van Hees Date: 2025-05-31 (Sat, 31 May 2025) Changed paths: M libdtrace/dt_prov_uprobe.c M test/triggers/Build R test/triggers/usdt-tst-deref-decode.c A test/triggers/usdt-tst-deref-decode.x86_64.c Log Message: ----------- WIP Signed-off-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/16bcd3190668...755e1ee438ea To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From eugene.loh at oracle.com Tue Jun 3 04:21:46 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Tue, 3 Jun 2025 00:21:46 -0400 Subject: [DTrace-devel] [PATCH] test: Adapt USDT PC search for USDT LTO changes Message-ID: <20250603042146.11894-1-eugene.loh@oracle.com> From: Eugene Loh To check USDT PCs, we looked at disassembly for characteristics that indicated USDT probes. With LTO, however, USDT instrumentation has changed. Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. Note that tst.pidargs.sh and tst.pidargmap.sh depend on tst.pidprobes.sh. Therefore, those tests also benefit from this change. They do not yet pass, however, since index 0 for args[] is said to be out of range. Signed-off-by: Eugene Loh --- libdtrace/dt_prov_uprobe.c | 2 +- test/unittest/usdt/tst.pidprobes.sh | 114 ++++++++++------------------ 2 files changed, 40 insertions(+), 76 deletions(-) diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index 26f513fe..aecb07d5 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -901,7 +901,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, pd.fun = ""; pd.prb = prb; -fprintf(stderr, "Underlying probe %s:%s:%s:%s @ %lx\n", psp->pps_prv, psp->pps_mod, psp->pps_fn, psp->pps_prb, psp->pps_off); +// fprintf(stderr, "Underlying probe %s:%s:%s:%s @ %lx\n", psp->pps_prv, psp->pps_mod, psp->pps_fn, psp->pps_prb, psp->pps_off); 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); uprp = dt_probe_lookup(dtp, &pd); diff --git a/test/unittest/usdt/tst.pidprobes.sh b/test/unittest/usdt/tst.pidprobes.sh index 0c75d796..6a1fa984 100755 --- a/test/unittest/usdt/tst.pidprobes.sh +++ b/test/unittest/usdt/tst.pidprobes.sh @@ -19,6 +19,7 @@ mapping=${3:-} # Set up test directory. +d=`pwd` DIRNAME=$tmpdir/pidprobes.$$.$RANDOM mkdir -p $DIRNAME cd $DIRNAME @@ -74,9 +75,6 @@ if [ $? -ne 0 ]; then echo "failed to compile test" >&2 exit 1 fi -if [[ `uname -m` = "aarch64" ]]; then - objdump -d main.o > disasm_foo.txt.before -fi $dtrace $dt_flags -G -64 -s prov.d main.o if [ $? -ne 0 ]; then echo "failed to create DOF" >&2 @@ -183,84 +181,50 @@ if [ `awk 'NF != 0 { print $1 }' dtrace.out | uniq | wc -l` -ne 1 ]; then fi pid=`awk 'NF != 0 { print $1 }' dtrace.out | uniq` -# From the disassembly, get the PCs for USDT probes. -# Check libdtrace/dt_link.c's arch-dependent dt_modtext() to see -# what sequence of instructions signal a USDT probe. - -if [[ `uname -m` = "x86_64" ]]; then - - # It is the first of five nop instructions in a row. - # So track pc[-6], pc[-5], pc[-4], pc[-3], pc[-2], pc[-1], pc[0] - # as well as whether they are nop. - - usdt_pcs_all=`awk ' - BEGIN { - pc6 = -1; is_nop6 = 0; - pc5 = -1; is_nop5 = 0; - pc4 = -1; is_nop4 = 0; - pc3 = -1; is_nop3 = 0; - pc2 = -1; is_nop2 = 0; - pc1 = -1; is_nop1 = 0; +# From showUSDT output, get the PCs for USDT probes. We look for output like: +# Note usdt, type N: +# Offset 0xoffset +# Function Offset 0xfoffset +# Probe pyramid::foo:entry +$d/test/utils/showUSDT main | awk ' +/^ *Note usdt, type / { + getline; + if (!match($0, /^ *Offset *0x[0-9a-f]* *$/)) { + print "ERROR: expect Offset"; + exit(1); } - { - # pc0 is current instruction - pc0 = strtonum("0x"$1); - - # decide whether it is a nop - is_nop0 = 0; - if (NF == 3 && - $2 == "90" && - $3 == "nop") - is_nop0 = 1; - - # report if pc[-5] is a USDT instruction - if (is_nop6 == 0 && - is_nop5 == 1 && - is_nop4 == 1 && - is_nop3 == 1 && - is_nop2 == 1 && - is_nop1 == 1 && - is_nop0 == 0) - print pc5; - - # prepare advance to next instruction - pc6 = pc5; is_nop6 = is_nop5; - pc5 = pc4; is_nop5 = is_nop4; - pc4 = pc3; is_nop4 = is_nop3; - pc3 = pc2; is_nop3 = is_nop2; - pc2 = pc1; is_nop2 = is_nop1; - pc1 = pc0; is_nop1 = is_nop0; - }' disasm_foo.txt` - - # We expect 4 USDT probes (2 USDT and 2 is-enabled). - if [ `echo $usdt_pcs_all | awk '{print NF}'` -ne 4 ]; then - echo ERROR: expected 4 USDT probes but got $usdt_pcs_all - cat disasm_foo.txt - exit 1 - fi + off = strtonum($2); - # Separate them into regular and is-enabled PCs. - # We assume they alternate. - usdt_pcs=`echo $usdt_pcs_all | awk '{ print $1, $3 }'` - usdt_pcs_isenabled=`echo $usdt_pcs_all | awk '{ print $2, $4 }'` + getline; + if (!match($0, /^ *Function Offset *0x[0-9a-f]* *$/)) { + print "ERROR: expect Function Offset"; + exit(1); + } -elif [[ `uname -m` = "aarch64" ]]; then + getline; + if (!match($0, /^ *Probe pyramid::foo:entry/)) { + print "ERROR: expect Probe pyramid::foo:entry"; + exit(1); + } - # The initial compilation of foo() makes it obvious where the - # USDT probes are. We just have to add the function offset in. - usdt_pcs=`awk '/<__dtrace_pyramid___entry>/ { print strtonum("0x"$1) + '$pc0' }' disasm_foo.txt.before` - usdt_pcs_isenabled=`awk '/<__dtraceenabled_pyramid___entry>/ { print strtonum("0x"$1) + '$pc0' }' disasm_foo.txt.before` + print off, $0; +} ' > usdt_pcs.txt +if [ $? -ne 0 ]; then + echo ERROR: showUSDT output to awk + $d/test/utils/showUSDT main + exit 1 +fi +usdt_pcs=`awk '!/is-enabled/ { sub("0x", ""); print $1}' usdt_pcs.txt` +usdt_pcs_isenabled=`awk '/is-enabled/ { sub("0x", ""); print $1}' usdt_pcs.txt` - # We expect 4 USDT probes (2 USDT and 2 is-enabled). - if [ `echo $usdt_pcs | awk '{print NF}'` -ne 2 -o \ - `echo $usdt_pcs_isenabled | awk '{print NF}'` -ne 2 ]; then - echo ERROR: expected 4 USDT probes but got $usdt_pcs and $usdt_pcs_isenabled - cat disasm_foo.txt.before - exit 1 - fi +# We expect 2 USDT probes plus 2 is-enabled. -else - echo ERROR unrecognized machine hardware name +if [ `echo $usdt_pcs | awk '{print NF}'` -ne 2 ]; then + echo ERROR: expected 2 USDT regular probes but got $usdt_pcs + exit 1 +fi +if [ `echo $usdt_pcs_isenabled | awk '{print NF}'` -ne 2 ]; then + echo ERROR: expected 2 USDT is-enabled probes but got $usdt_pcs_isenabled exit 1 fi -- 2.43.5 From eugene.loh at oracle.com Tue Jun 3 20:35:32 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Tue, 3 Jun 2025 16:35:32 -0400 Subject: [DTrace-devel] [PATCH] test: Make the USDT "only enabled" test more stringent Message-ID: <20250603203532.20743-1-eugene.loh@oracle.com> From: Eugene Loh What if a program has an is-enabled probe without the corresponding parent probe? It should at least compile, and we test that. Add more checks to the test: - the is-enabled branch is not taken when run without dtrace - the parent USDT probe is listed with "dtrace -l" - the is-enabled branch is not taken even when run with dtrace if the parent probe is not enabled - the is-enabled branch is taken when run with dtrace and the parent probe is enabled; however, the parent probe does not fire since it is not in the test trigger Signed-off-by: Eugene Loh --- test/unittest/usdt/tst.onlyenabled.r | 21 ++++++++++++++++++ test/unittest/usdt/tst.onlyenabled.sh | 32 ++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 test/unittest/usdt/tst.onlyenabled.r diff --git a/test/unittest/usdt/tst.onlyenabled.r b/test/unittest/usdt/tst.onlyenabled.r new file mode 100644 index 00000000..93cb402c --- /dev/null +++ b/test/unittest/usdt/tst.onlyenabled.r @@ -0,0 +1,21 @@ +run without dtrace +USDT probe is not enabled + +USDT probes found: +NNN test_provNNN test main go + +run with dtrace but not the USDT probe +USDT probe is not enabled + FUNCTION:NAME + :BEGIN BEGIN probe fired + + + +run with dtrace and with the USDT probe +USDT probe is enabled + +-- @@stderr -- +dtrace: description 'BEGIN + ' matched 1 probe +dtrace: description 'test_prov$target:::go + ' matched 1 probe diff --git a/test/unittest/usdt/tst.onlyenabled.sh b/test/unittest/usdt/tst.onlyenabled.sh index d3487834..d1859bbc 100755 --- a/test/unittest/usdt/tst.onlyenabled.sh +++ b/test/unittest/usdt/tst.onlyenabled.sh @@ -5,6 +5,7 @@ # Licensed under the Universal Permissive License v 1.0 as shown at # http://oss.oracle.com/licenses/upl. # +# @@nosort if [ $# != 1 ]; then echo expected one argument: '<'dtrace-path'>' exit 2 @@ -32,6 +33,7 @@ if [ $? -ne 0 ]; then fi cat > test.c < #include #include "prov.h" @@ -39,7 +41,9 @@ int main(int argc, char **argv) { if (TEST_PROV_GO_ENABLED()) - return 2; + printf("USDT probe is enabled\n"); + else + printf("USDT probe is not enabled\n"); return 0; } @@ -61,4 +65,30 @@ if [ $? -ne 0 ]; then exit 1 fi +# Test compiled, but does it run correctly? +echo run without dtrace +./test + +echo +echo USDT probes found: +$dtrace $dt_flags -c ./test -lP 'test_prov$target' \ +|& awk '/test_prov/ { gsub(/[0-9]+/, "NNN"); print $1, $2, $3, $4, $5; }' + +echo +echo run with dtrace but not the USDT probe +$dtrace $dt_flags -c ./test -n 'BEGIN + { + printf("BEGIN probe fired\n"); + exit(0); + }' -o dt.out +cat dt.out # report dtrace output after trigger output + +echo +echo run with dtrace and with the USDT probe +$dtrace $dt_flags -c ./test -n 'test_prov$target:::go + { + printf("ERROR: USDT probe fired!\n"); + exit(1); + }' + exit 0 -- 2.43.5 From eugene.loh at oracle.com Tue Jun 3 21:08:34 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Tue, 3 Jun 2025 17:08:34 -0400 Subject: [DTrace-devel] [PATCH v2 1/2] Omit an aggregation record if [u][sym|mod] translation fails Message-ID: <20250603210834.21204-1-eugene.loh@oracle.com> From: Eugene Loh An aggregation key can be a sym(), mod(), usym(), or umod() translation of an address. It is passed from producer to user space as an address, and the consumer must translate the address. It is possible for the translation to fail. Omit a record if the translation fails. This addresses failures seen before OL9 in test/unittest/profile-n/tst.ufunc.sh test/unittest/profile-n/tst.usym.sh The problem was that the kernel's aggregation buffers are snapshot multiple times. If a translation ever fails, the raw address is used instead. Later on, when the aggregation is printed, if the translation is successful, the raw key will report a count of 0. E.g., we snapshot an aggregation. The translation of address 0xabcedf fails and so the key remains 0xabcdef. Later the aggregation is printed and, therefore, again snapshot. The values are cleared. This time the translation of the address -- say to the function starting at 0xabcd00 -- is successful. That aggregation key is successfully and correctly reported, but the the raw 0xabcdef will mysteriously be reported with a count 0. It may be argued that some users would like to see addresses that could not be translated, but typically those unsuccessful addresses are not very meaningful. Signed-off-by: Eugene Loh --- libdtrace/dt_aggregate.c | 51 ++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/libdtrace/dt_aggregate.c b/libdtrace/dt_aggregate.c index a18de3a75..32b0faced 100644 --- a/libdtrace/dt_aggregate.c +++ b/libdtrace/dt_aggregate.c @@ -317,61 +317,76 @@ dt_aggregate_quantizedcmp(int64_t *lhs, int64_t *rhs) return 0; } -static void +static int dt_aggregate_usym(dtrace_hdl_t *dtp, uint64_t *data) { uint64_t tgid = data[0]; uint64_t *pc = &data[1]; pid_t pid; GElf_Sym sym; + int rc = 0; if (dtp->dt_vector != NULL) - return; + return -1; pid = dt_proc_grab_lock(dtp, tgid, DTRACE_PROC_WAITING | DTRACE_PROC_SHORTLIVED); if (pid < 0) - return; + return -1; if (dt_Plookup_by_addr(dtp, pid, *pc, NULL, &sym) == 0) *pc = sym.st_value; + else + rc = -1; dt_proc_release_unlock(dtp, pid); + + return rc; } -static void +static int dt_aggregate_umod(dtrace_hdl_t *dtp, uint64_t *data) { uint64_t tgid = data[0]; uint64_t *pc = &data[1]; pid_t pid; const prmap_t *map; + int rc = 0; if (dtp->dt_vector != NULL) - return; + return -1; pid = dt_proc_grab_lock(dtp, tgid, DTRACE_PROC_WAITING | DTRACE_PROC_SHORTLIVED); if (pid < 0) - return; + return -1; if ((map = dt_Paddr_to_map(dtp, pid, *pc)) != NULL) *pc = map->pr_vaddr; + else + rc = -1; dt_proc_release_unlock(dtp, pid); + + return rc; } -static void +static int dt_aggregate_sym(dtrace_hdl_t *dtp, uint64_t *data) { GElf_Sym sym; uint64_t *pc = data; + int rc = 0; if (dtrace_lookup_by_addr(dtp, *pc, &sym, NULL) == 0) *pc = sym.st_value; + else + rc = -1; + + return rc; } -static void +static int dt_aggregate_mod(dtrace_hdl_t *dtp, uint64_t *addr) { dt_module_t *dmp; @@ -385,7 +400,7 @@ dt_aggregate_mod(dtrace_hdl_t *dtp, uint64_t *addr) * appear more than once in aggregation output). It seems * unlikely that anyone will ever notice or care... */ - return; + return -1; } for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; @@ -400,7 +415,7 @@ dt_aggregate_mod(dtrace_hdl_t *dtp, uint64_t *addr) dtrace_addr_range_cmp) != NULL) { *addr = dmp->dm_text_addrs[0].dar_va; - return; + return 0; } if (dmp->dm_data_addrs != NULL && @@ -413,9 +428,11 @@ dt_aggregate_mod(dtrace_hdl_t *dtp, uint64_t *addr) else *addr = dmp->dm_data_addrs[0].dar_va; - return; + return 0; } } + + return -1; } static dtrace_aggid_t @@ -574,16 +591,20 @@ dt_aggregate_snap_one(dtrace_hdl_t *dtp, int aggid, int cpu, const char *key, switch(agg->dtagd_krecs[i].dtrd_action) { case DTRACEACT_USYM: - dt_aggregate_usym(dtp, p); + if (dt_aggregate_usym(dtp, p) == -1) + return 0; break; case DTRACEACT_UMOD: - dt_aggregate_umod(dtp, p); + if (dt_aggregate_umod(dtp, p) == -1) + return 0; break; case DTRACEACT_SYM: - dt_aggregate_sym(dtp, p); + if (dt_aggregate_sym(dtp, p) == -1) + return 0; break; case DTRACEACT_MOD: - dt_aggregate_mod(dtp, p); + if (dt_aggregate_mod(dtp, p) == -1) + return 0; break; default: break; -- 2.43.5 From noreply at github.com Thu Jun 5 14:57:11 2025 From: noreply at github.com (Kris Van Hees) Date: Thu, 05 Jun 2025 07:57:11 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] aa6366: test: allow overriding CC, OBJCOPY, OBJDUMP, NM, ... Message-ID: Branch: refs/heads/kvh/usdt-dev Home: https://github.com/oracle/dtrace-utils Commit: aa63660a7cfcdeb1daf4fb63f1c15f75a1693064 https://github.com/oracle/dtrace-utils/commit/aa63660a7cfcdeb1daf4fb63f1c15f75a1693064 Author: Eugene Loh Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M runtest.sh M test/expensive/locking/tst.DestructionDoubleUnlock.sh M test/internals/headers/tst.header-endianness.sh M test/stress/options/tst.cpu-syscall.sh M test/unittest/aggs/tst.aggmod_full2.sh M test/unittest/arrays/tst.uregsarray-check.sh M test/unittest/bitfields/tst.bitfield-offset.x M test/unittest/builtinvar/tst.errno3.sh M test/unittest/builtinvar/tst.tid_pid.sh M test/unittest/dtrace-util/tst.ListProbesArgsUSDT.sh M test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh M test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh M test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh M test/unittest/fbtprovider/tst.entryargs2.sh M test/unittest/funcs/copyout/tst.copyout.sh M test/unittest/funcs/copyoutstr/tst.copyoutstr.sh M test/unittest/misc/tst.include.sh M test/unittest/options/tst.cpu-syscall.sh M test/unittest/options/tst.ctypes.sh M test/unittest/options/tst.dtypes.sh M test/unittest/options/tst.linktype.sh M test/unittest/options/tst.strip.sh M test/unittest/pid/tst.dash.sh M test/unittest/pid/tst.offsets.sh M test/unittest/pid/tst.provregex1.sh M test/unittest/pid/tst.provregex2.sh M test/unittest/pid/tst.provregex3.sh M test/unittest/pid/tst.provregex4.sh M test/unittest/usdt/tst.allargs.sh M test/unittest/usdt/tst.badguess.sh M test/unittest/usdt/tst.badguess.x M test/unittest/usdt/tst.dlclose1.sh M test/unittest/usdt/tst.dlclose2.sh M test/unittest/usdt/tst.dlclose3.sh M test/unittest/usdt/tst.dlclose4.sh M test/unittest/usdt/tst.eliminate.sh M test/unittest/usdt/tst.enable_pid.sh M test/unittest/usdt/tst.enabled.sh M test/unittest/usdt/tst.enabled2.sh M test/unittest/usdt/tst.entryreturn.sh M test/unittest/usdt/tst.exec-dof-replacement.sh M test/unittest/usdt/tst.execstack.sh M test/unittest/usdt/tst.fork.sh M test/unittest/usdt/tst.guess32.sh M test/unittest/usdt/tst.guess64.sh M test/unittest/usdt/tst.header.sh M test/unittest/usdt/tst.lingering.sh M test/unittest/usdt/tst.link-idempotence.sh M test/unittest/usdt/tst.linkpriv.sh M test/unittest/usdt/tst.linkunpriv.sh M test/unittest/usdt/tst.manyprobes.sh M test/unittest/usdt/tst.manyprocs.sh M test/unittest/usdt/tst.multiple.sh M test/unittest/usdt/tst.multiprov-dupprobe-shlibs.sh M test/unittest/usdt/tst.multitrace.sh M test/unittest/usdt/tst.nusdtprobes.sh M test/unittest/usdt/tst.onlyenabled.sh M test/unittest/usdt/tst.pidprobes.sh M test/unittest/usdt/tst.pie.sh M test/unittest/usdt/tst.reeval.sh M test/unittest/usdt/tst.static.sh M test/unittest/usdt/tst.static2.sh M test/unittest/usdt/tst.user.sh M test/utils/workload_analyze_loop.sh Log Message: ----------- test: allow overriding CC, OBJCOPY, OBJDUMP, NM, ... Bug: https://github.com/oracle/dtrace-utils/issues/75 Signed-off-by: Sam James Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Commit: 253a2277c7fce4aec8cc07f0fe54e5d29bdb9365 https://github.com/oracle/dtrace-utils/commit/253a2277c7fce4aec8cc07f0fe54e5d29bdb9365 Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M libdtrace/dt_provider.c M libdtrace/dt_provider.h Log Message: ----------- provider: fix registering fbt and rawfbt twice Now that rawfbt has been integrated into the fbt provider, it no longer needs to be in the list of providers to call populate() in. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 044d4681ddf4e99604a1dfcad4c4b514cd5c80cc https://github.com/oracle/dtrace-utils/commit/044d4681ddf4e99604a1dfcad4c4b514cd5c80cc Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M libdtrace/dt_provider.c Log Message: ----------- providers: loop through all providers for discovery The discovery of probes was tied to the static list of providers that are called on init. It should iterate over all providers that are in fact registered, i.e. the dt_provs hash. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 957ce7e2a590470fa9fe982317ca3009a7cf6747 https://github.com/oracle/dtrace-utils/commit/957ce7e2a590470fa9fe982317ca3009a7cf6747 Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M libdtrace/dt_open.c M libdtrace/dt_version.h Log Message: ----------- Only include dt_git_version.h where needed Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 9061638d42532ce890f56eed1edabb8ce244a433 https://github.com/oracle/dtrace-utils/commit/9061638d42532ce890f56eed1edabb8ce244a433 Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M libcommon/dof_parser.c Log Message: ----------- dof_parser: remove pointless comment Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: c19d4db84fc5dc36bff06fbc1b480048a1f0f0ec https://github.com/oracle/dtrace-utils/commit/c19d4db84fc5dc36bff06fbc1b480048a1f0f0ec Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M dtprobed/dtprobed.c M libcommon/dof_parser.c M libcommon/dof_parser.h Log Message: ----------- dof_parser: restructure the dof_copyin*() code All logic for reading data from the DOF parser pipe is now consolidated in dof_copyin(). Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: a15a0a66623ece6d8af2a56d6caeb88296cf2102 https://github.com/oracle/dtrace-utils/commit/a15a0a66623ece6d8af2a56d6caeb88296cf2102 Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M dtprobed/dof_stash.c M dtprobed/dof_stash.h M dtprobed/dtprobed.c M libcommon/Build R libcommon/dof_parser.c R libcommon/dof_parser.h R libcommon/dof_parser_host.c A libcommon/usdt_parser.c A libcommon/usdt_parser.h A libcommon/usdt_parser_dof.c A libcommon/usdt_parser_host.c M libdtrace/dt_pid.c Log Message: ----------- dof_parser: generic parser framework to support multiple parsers To prepare for non-DOF section based USDT probe definitions, the data passed from dtprobed to the USDT data parser is more generic. The dof_helper_t structure is passed first, followed by a block count, and that number of data blocks, passed as a size followed by the content. Signed-off-by: Kris Van Hees Commit: b02cdc4ec113552c2f0e943a76e603c8154f68e5 https://github.com/oracle/dtrace-utils/commit/b02cdc4ec113552c2f0e943a76e603c8154f68e5 Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M dtprobed/dtprobed.c Log Message: ----------- dtprobed: fix probe name debug output Debug output while reading dof_parsed_t structures was printing the probe names as provider->provoder.name and probe->probe.name, but probe.name is a 0-separated concatenation of the probe name elements. It only printed the module name. Corrected to print the full probe name. Also moved it to the proper place (when a new probe is read rather than for every tracepoint). Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Reviewed-by: Eugene Loh Commit: 026174af82d129762a7686e2daeeb3dbd8de14c1 https://github.com/oracle/dtrace-utils/commit/026174af82d129762a7686e2daeeb3dbd8de14c1 Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M libcommon/Build A libcommon/dt_htab.c A libcommon/dt_htab.h M libdtrace/Build M libdtrace/dt_consume.c R libdtrace/dt_htab.c R libdtrace/dt_htab.h M libdtrace/dt_kernel_module.c M libdtrace/dt_module.c M libdtrace/dt_open.c M libdtrace/dt_probe.c M libdtrace/dt_provider.c M libdtrace/dt_symtab.c Log Message: ----------- htab: move htab handling to libcommon Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: bef060dd5572e3cbd9d0433d1698a8d52744a9c2 https://github.com/oracle/dtrace-utils/commit/bef060dd5572e3cbd9d0433d1698a8d52744a9c2 Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M libcommon/dt_htab.c M libcommon/dt_htab.h M libdtrace/dt_string.c M libdtrace/dt_string.h Log Message: ----------- htab: move str2hval() to dt_htab Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 760b2021402b6e30f4075d453a219cb96c9604d9 https://github.com/oracle/dtrace-utils/commit/760b2021402b6e30f4075d453a219cb96c9604d9 Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M dtprobed/dtprobed.c Log Message: ----------- dtprobed: make sure that retry one time means exactly that Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: fb16c26a8b8a878110efc91dc6c0e8abc7d0aea8 https://github.com/oracle/dtrace-utils/commit/fb16c26a8b8a878110efc91dc6c0e8abc7d0aea8 Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M include/dtrace/ioctl.h Log Message: ----------- usdt: add HASUSDT to the helper ioctl interface Signed-off-by: Kris Van Hees Commit: 699ffd67768912326c1a274cd8b33cd1676c0ccb https://github.com/oracle/dtrace-utils/commit/699ffd67768912326c1a274cd8b33cd1676c0ccb Author: Kris Van Hees Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M dtprobed/dof_stash.c M dtprobed/dof_stash.h M dtprobed/dtprobed.c M libcommon/Build M libcommon/usdt_parser.c M libcommon/usdt_parser.h M libcommon/usdt_parser_dof.c M libcommon/usdt_parser_host.c A libcommon/usdt_parser_notes.c Log Message: ----------- dtprobed, usdt parser: add support for ELF notes-based USDT Signed-off-by: Kris Van Hees Commit: 8f020a9b6c9c591adbac06c78c6e538f4352f4e6 https://github.com/oracle/dtrace-utils/commit/8f020a9b6c9c591adbac06c78c6e538f4352f4e6 Author: Kris Van Hees Date: 2025-06-04 (Wed, 04 Jun 2025) Changed paths: M include/dtrace/pid.h M libdtrace/dt_cg.c M libdtrace/dt_cg.h M libdtrace/dt_pid.c M libdtrace/dt_prov_uprobe.c Log Message: ----------- usdt: implement tracing USDT probes specified in ELF notes Commit: d8a8ed0dcac18e5cb8b93e5db608f0991b7f80a0 https://github.com/oracle/dtrace-utils/commit/d8a8ed0dcac18e5cb8b93e5db608f0991b7f80a0 Author: Kris Van Hees Date: 2025-06-04 (Wed, 04 Jun 2025) Changed paths: M libdtrace/drti.c M libdtrace/dt_dof.c M libdtrace/dt_impl.h M libdtrace/dt_link.c M libdtrace/dt_program.c M test/triggers/Build A test/triggers/usdt-tst-arg-const-prov.d A test/triggers/usdt-tst-arg-const.c A test/triggers/usdt-tst-arg-reg-prov.d A test/triggers/usdt-tst-arg-reg.c A test/triggers/usdt-tst-deref-decode-prov.d A test/triggers/usdt-tst-deref-decode.x86_64.c M test/unittest/options/tst.strip.sh A test/unittest/usdt/err.wrong-probe-argc-cc.sh A test/unittest/usdt/err.wrong-probe-argc-rt.sh A test/unittest/usdt/err.wrong-probe.sh A test/unittest/usdt/err.wrong-prov.sh A test/unittest/usdt/tst.arg-reg.d A test/unittest/usdt/tst.arg-reg.r R test/unittest/usdt/tst.badguess.sh R test/unittest/usdt/tst.badguess.x A test/unittest/usdt/tst.const.d A test/unittest/usdt/tst.const.r A test/unittest/usdt/tst.deref-decode.d R test/unittest/usdt/tst.guess32.sh R test/unittest/usdt/tst.guess32.x M test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p M test/utils/Build M test/utils/showUSDT.c M uts/common/sys/sdt.h A uts/common/sys/usdt.h A uts/common/sys/usdt_gennote.h A uts/common/sys/usdt_internal.h Log Message: ----------- link: implement USDT probe definitions in ELF notes Signed-off-by: Kris Van Hees Commit: 4130200018dfb73a10fea25d2b0d258202db54f0 https://github.com/oracle/dtrace-utils/commit/4130200018dfb73a10fea25d2b0d258202db54f0 Author: Kris Van Hees Date: 2025-06-04 (Wed, 04 Jun 2025) Changed paths: M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh Log Message: ----------- test: fix test for non-installed testing On a system without DTrace installed, cannot be found, causing this test to fail. Use test_cppflags to ensure the correct location is used in all cases. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 5df9f82752aeec800daf7e066832ce28e08bdff9 https://github.com/oracle/dtrace-utils/commit/5df9f82752aeec800daf7e066832ce28e08bdff9 Author: Eugene Loh Date: 2025-06-04 (Wed, 04 Jun 2025) Changed paths: M test/unittest/usdt/tst.pidprobes.sh Log Message: ----------- test: Adapt USDT PC search for USDT LTO changes To check USDT PCs, we looked at disassembly for characteristics that indicated USDT probes. With LTO, however, USDT instrumentation has changed. Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. Note that tst.pidargs.sh and tst.pidargmap.sh depend on tst.pidprobes.sh. Therefore, those tests also benefit from this change. They do not yet pass, however, since index 0 for args[] is said to be out of range. Signed-off-by: Eugene Loh Commit: 2ac3202150dd485d7d08dbefd351418bb0e07879 https://github.com/oracle/dtrace-utils/commit/2ac3202150dd485d7d08dbefd351418bb0e07879 Author: Kris Van Hees Date: 2025-06-05 (Thu, 05 Jun 2025) Changed paths: M dtprobed/dof_stash.c Log Message: ----------- ADD TO dtprobed PATCH Signed-off-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/755e1ee438ea...2ac3202150dd To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From alan.maguire at oracle.com Thu Jun 5 21:33:39 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Thu, 5 Jun 2025 22:33:39 +0100 Subject: [DTrace-devel] [RFC PATCH 0/2] DTrace TCP provider Message-ID: <20250605213341.1410405-1-alan.maguire@oracle.com> This series is a first draft of TCP provider support, where the probes are implemented via underlying fbt and sdt probes. Due to the use of the sock/inet_sock_set_state tracepoint, intended for ~5.15 kernels and later. Tried replacing this with fbt::tcp_set_state:entry but this misses a few state transitions. A few things that need tidying up; haul get_member() functionality duplicated in dt_prov_tcp.c from dt_prov_ip.c into a common function (in dt_cg.c maybe?). Note that we needed to bump the DT_STRING_SLOTS to 8 to prevent assert failures; likely a result of the complex translator dances with inet_ntoa*()s etc. All tests under test/unitest/tcp pass unmodified on an upstream (6.15) kernel. For 5.15, we see missing state-change to SYN_RECV; on further inspection it appears that while the probe fires, we do not get accurate IP address info in args[2]. This works on upstream, so it may be that something changed in clone socket logic as we call the probe with the newsk. Goes without saying needs more testing and cleanups, but does implement all TCP provider probes: accept-established, accept-refused, connnect-request, connect-established, connect-refused, receive, send, state-change so it's a start at least. Alan Maguire (2): dtrace: add tcp provider dtrace: sync dlibs with tcp.d, ip.d and net.d changes dlibs/aarch64/5.14/ip.d | 1 - dlibs/aarch64/5.14/net.d | 6 +- dlibs/aarch64/5.14/tcp.d | 43 +++-- dlibs/aarch64/5.16/ip.d | 1 - dlibs/aarch64/5.16/net.d | 6 +- dlibs/aarch64/5.16/tcp.d | 43 +++-- dlibs/aarch64/6.1/ip.d | 1 - dlibs/aarch64/6.1/net.d | 6 +- dlibs/aarch64/6.1/tcp.d | 43 +++-- dlibs/aarch64/6.10/ip.d | 1 - dlibs/aarch64/6.10/net.d | 6 +- dlibs/aarch64/6.10/tcp.d | 43 +++-- dlibs/x86_64/5.14/ip.d | 1 - dlibs/x86_64/5.14/net.d | 6 +- dlibs/x86_64/5.14/tcp.d | 43 +++-- dlibs/x86_64/5.16/ip.d | 1 - dlibs/x86_64/5.16/net.d | 6 +- dlibs/x86_64/5.16/tcp.d | 43 +++-- dlibs/x86_64/6.1/ip.d | 1 - dlibs/x86_64/6.1/net.d | 6 +- dlibs/x86_64/6.1/tcp.d | 43 +++-- dlibs/x86_64/6.10/ip.d | 1 - dlibs/x86_64/6.10/net.d | 6 +- dlibs/x86_64/6.10/tcp.d | 43 +++-- libdtrace/Build | 2 + libdtrace/dt_impl.h | 2 +- libdtrace/dt_prov_tcp.c | 397 +++++++++++++++++++++++++++++++++++++++ libdtrace/dt_provider.c | 1 + libdtrace/dt_provider.h | 1 + libdtrace/ip.d | 1 - libdtrace/net.d | 6 +- libdtrace/tcp.d | 43 +++-- 32 files changed, 654 insertions(+), 199 deletions(-) create mode 100644 libdtrace/dt_prov_tcp.c -- 2.43.5 From alan.maguire at oracle.com Thu Jun 5 21:33:40 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Thu, 5 Jun 2025 22:33:40 +0100 Subject: [DTrace-devel] [RFC 1/2] dtrace: add tcp provider In-Reply-To: <20250605213341.1410405-1-alan.maguire@oracle.com> References: <20250605213341.1410405-1-alan.maguire@oracle.com> Message-ID: <20250605213341.1410405-2-alan.maguire@oracle.com> Based upon various fbt probe points support TCP send, receive, state-change, accept-established, accept-refused, connect-request, connect-established and connect-refused probes. A few tweaks were needed to tcp.d to support the probes fully. Signed-off-by: Alan Maguire --- libdtrace/Build | 2 + libdtrace/dt_impl.h | 2 +- libdtrace/dt_prov_tcp.c | 397 ++++++++++++++++++++++++++++++++++++++++ libdtrace/dt_provider.c | 1 + libdtrace/dt_provider.h | 1 + libdtrace/ip.d | 1 - libdtrace/net.d | 6 +- libdtrace/tcp.d | 43 +++-- 8 files changed, 430 insertions(+), 23 deletions(-) create mode 100644 libdtrace/dt_prov_tcp.c diff --git a/libdtrace/Build b/libdtrace/Build index 7e6e8a38..a5439354 100644 --- a/libdtrace/Build +++ b/libdtrace/Build @@ -59,6 +59,7 @@ libdtrace-build_SOURCES = dt_aggregate.c \ dt_prov_sched.c \ dt_prov_sdt.c \ dt_prov_syscall.c \ + dt_prov_tcp.c \ dt_prov_uprobe.c \ dt_provider.c \ dt_provider_sdt.c \ @@ -117,6 +118,7 @@ dt_prov_rawtp.c_CFLAGS := -Wno-pedantic dt_prov_sched.c_CFLAGS := -Wno-pedantic dt_prov_sdt.c_CFLAGS := -Wno-pedantic dt_prov_syscall.c_CFLAGS := -Wno-pedantic +dt_prov_tcp.c_CFLAGS := -Wno-pedantic dt_prov_uprobe.c_CFLAGS := -Wno-pedantic dt_debug.c_CFLAGS := -Wno-prio-ctor-dtor diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h index 68fb8ec5..10424f9c 100644 --- a/libdtrace/dt_impl.h +++ b/libdtrace/dt_impl.h @@ -218,7 +218,7 @@ typedef struct dt_kern_path { * - cleanpath() holds a prepended '/' char, a string, an appended '/' char, * and a terminating NUL char, or STRSZ + 3 chars altogether */ -#define DT_TSTRING_SLOTS 4 +#define DT_TSTRING_SLOTS 8 #define DT_TSTRING_SIZE(dtp) \ MAX(P2ROUNDUP((dtp)->dt_options[DTRACEOPT_STRSIZE] + 3, 8), \ 72) diff --git a/libdtrace/dt_prov_tcp.c b/libdtrace/dt_prov_tcp.c new file mode 100644 index 00000000..cdc9ca45 --- /dev/null +++ b/libdtrace/dt_prov_tcp.c @@ -0,0 +1,397 @@ +/* + * 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. + * + * The 'tcp' SDT provider for DTrace-specific probes. + */ +#include +#include + +#include "dt_dctx.h" +#include "dt_cg.h" +#include "dt_provider_sdt.h" +#include "dt_probe.h" + +static const char prvname[] = "tcp"; +static const char modname[] = "vmlinux"; + +enum { + NET_PROBE_OUTBOUND = 0, + NET_PROBE_INBOUND, + NET_PROBE_STATE +}; + +static probe_dep_t probes[] = { + /* does not fire on UEK7 unless rawfbt; no idea why... */ + { "accept-established", + DTRACE_PROBESPEC_NAME, "rawfbt::tcp_init_transfer:entry" }, + { "accept-refused", + DTRACE_PROBESPEC_NAME, "fbt::tcp_v4_send_reset:entry" }, + { "accept-refused", + DTRACE_PROBESPEC_NAME, "fbt::tcp_v6_send_reset:entry" }, + { "connect-established", + DTRACE_PROBESPEC_NAME, "fbt::tcp_finish_connect:entry" }, + { "connect-refused", + DTRACE_PROBESPEC_NAME, "fbt::tcp_reset:entry" }, + { "connect-request", + DTRACE_PROBESPEC_NAME, "fbt::ip_queue_xmit:entry" }, + /* ip6_xmit has > 6 args so cannot fentry on aarch64; use rawfbt */ + { "connect-request", + DTRACE_PROBESPEC_NAME, "rawfbt::ip6_xmit:entry" }, + { "receive", + DTRACE_PROBESPEC_NAME, "fbt::tcp_rcv_established:entry" }, + { "receive", + DTRACE_PROBESPEC_NAME, "fbt::tcp_rcv_state_process:entry" }, + { "receive", + DTRACE_PROBESPEC_NAME, "fbt::tcp_v4_send_reset:entry" }, + { "send", + DTRACE_PROBESPEC_NAME, "fbt::ip_queue_xmit:entry" }, + /* ip_send_unicast_reply has 10 args so cannot fentry; use rawfbt */ + { "send", + DTRACE_PROBESPEC_NAME, "rawfbt::ip_send_unicast_reply:entry" }, + { "send", + DTRACE_PROBESPEC_NAME, "fbt::ip_build_and_send_pkt" }, + /* ip6_xmit has > 6 args so cannot fentry on aarch64; use rawfbt */ + { "send", + DTRACE_PROBESPEC_NAME, "rawfbt::ip6_xmit:entry" }, + { "state-change", + DTRACE_PROBESPEC_NAME, "sdt:::inet_sock_set_state" }, + { "state-change", + DTRACE_PROBESPEC_NAME, "fbt::tcp_time_wait:entry" }, + { NULL, } +}; + +static probe_arg_t probe_args[] = { + { "accept-established", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "accept-established", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "accept-established", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } }, + { "accept-established", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "accept-established", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "accept-established", 5, { 5, 0, "unsigned char", "int"} }, + { "accept-established", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "accept-established", 7, { 7, 0, "int", "int" } }, + + { "accept-refused", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "accept-refused", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "accept-refused", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } }, + { "accept-refused", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "accept-refused", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "accept-refused", 5, { 5, 0, "unsigned char", "int"} }, + { "accept-refused", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "accept-refused", 7, { 7, 0, "int", "int" } }, + + { "connect-established", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "connect-established", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "connect-established", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } }, + { "connect-established", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "connect-established", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "connect-established", 5, { 5, 0, "unsigned char", "int"} }, + { "connect-established", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "connect-established", 7, { 7, 0, "int", "int" } }, + + { "connect-refused", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "connect-refused", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "connect-refused", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } }, + { "connect-refused", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "connect-refused", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "connect-refused", 5, { 5, 0, "unsigned char", "int"} }, + { "connect-refused", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "connect-refused", 7, { 7, 0, "int", "int" } }, + + { "connect-request", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "connect-request", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "connect-request", 2, { 2, 0, "__dtrace_tcp_void_ip_t *", "ipinfo_t *" } }, + { "connect-request", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "connect-request", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "connect-request", 5, { 5, 0, "unsigned char", "int"} }, + { "connect-request", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "connect-request", 7, { 7, 0, "int", "int" } }, + + { "receive", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "receive", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "receive", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } }, + { "receive", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "receive", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "receive", 5, { 5, 0, "unsigned char", "int"} }, + { "receive", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "receive", 7, { 7, 0, "int", "int" } }, + + { "send", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "send", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "send", 2, { 2, 0, "__dtrace_tcp_void_ip_t *", "ipinfo_t *" } }, + { "send", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "send", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "send", 5, { 5, 0, "unsigned char", "int"} }, + { "send", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "send", 7, { 7, 0, "int", "int" } }, + + { "state-change", 0, { 0, 0, "void *", "void *", } }, + { "state-change", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "state-change", 2, { 2, 0, "void *", "void *" } }, + { "state-change", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "state-change", 4, { 4, 0, "void *", "void *" } }, + { "state-change", 5, { 5, 0, "void *", "void *" } }, + { "state-change", 6, { 6, 0, "struct sock *", "tcplsinfo_t *" } }, + { "state-change", 7, { 7, 0, "int", "int" } }, + + { NULL, } +}; + +static const dtrace_pattr_t pattr = { +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +}; + +/* + * Provide all the "tcp" SDT probes. + */ +static int populate(dtrace_hdl_t *dtp) +{ + return dt_sdt_populate(dtp, prvname, modname, &dt_tcp, &pattr, + probe_args, probes); +} + +/* + * Retrieve the value of a member in a given struct. + * + * Entry: + * reg = TYPE *ptr + * + * Return: + * %r0 = ptr->member + * Clobbers: + * %r1 .. %r5 + */ +static int get_member(dt_pcb_t *pcb, const char *name, int reg, + const char *member) { + dtrace_hdl_t *dtp = pcb->pcb_hdl; + dt_irlist_t *dlp = &pcb->pcb_ir; + dtrace_typeinfo_t tt; + ctf_membinfo_t ctm; + size_t size; + uint_t ldop; + + if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_KMODS, name, &tt) == -1 || + ctf_member_info(tt.dtt_ctfp, tt.dtt_type, member, &ctm) == CTF_ERR) + return -1; + + ldop = dt_cg_ldsize(NULL, tt.dtt_ctfp, ctm.ctm_type, &size); + + emit(dlp, BPF_MOV_REG(BPF_REG_3, reg)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, ctm.ctm_offset / NBBY)); + emit(dlp, BPF_MOV_IMM(BPF_REG_2, size)); + emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_BASE)); + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_kernel])); + emit(dlp, BPF_LOAD(ldop, BPF_REG_0, BPF_REG_FP, DT_TRAMP_SP_BASE)); + + return 0; +} + +/* + * Generate a BPF trampoline for a SDT probe. + * + * The trampoline function is called when a SDT probe triggers, and it must + * satisfy the following prototype: + * + * int dt_tcp(void *data) + * + * The trampoline will populate a dt_dctx_t struct and then call the function + * that implements the compiled D clause. It returns the value that it gets + * back from that function. + */ +static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) +{ + dt_irlist_t *dlp = &pcb->pcb_ir; + dt_probe_t *prp = pcb->pcb_probe; + dt_probe_t *uprp = pcb->pcb_parent_probe; + int direction, have_iphdr; + int skarg = 0, skbarg = 1, tcparg = 0; + int skarg_maybe_null; + int skstate = 0; + + if (strcmp(prp->desc->prb, "state-change") == 0) { + int newstatearg; + + if (strcmp(uprp->desc->fun, "tcp_time_wait") == 0) + newstatearg = 1; + else + newstatearg = 2; + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(0))); + emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_6, 0, exitlbl)); + /* check it is a TCP socket */ + get_member(pcb, "struct sock", BPF_REG_6, "sk_protocol"); + emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, 6, exitlbl)); + + /* save sk */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(0))); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(3), BPF_REG_6)); + + /* save new state */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(newstatearg))); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(6), BPF_REG_6)); + + /* save sk */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(3))); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_6)); + + /* save empty args */ + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(0), 0)); + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(2), 0)); + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(4), 0)); + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(5), 0)); + + /* NET_PROBE_STATE */ + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(7), + NET_PROBE_STATE)); + return 0; + } + + if (strcmp(prp->desc->prb, "accept-established") == 0) { + direction = NET_PROBE_OUTBOUND; + have_iphdr = 1; + /* skb in arg2 not arg1 */ + skbarg = 2; + skarg_maybe_null = 0; + /* ensure arg1 is BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(1))); + emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_6, + BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB, + exitlbl)); + } else if (strcmp(prp->desc->prb, "receive") == 0 || + strcmp(prp->desc->prb, "accept-refused") == 0) { + direction = NET_PROBE_INBOUND; + have_iphdr = 1; + if (strcmp(uprp->desc->fun, "tcp_v4_send_reset") == 0 || + strcmp(uprp->desc->fun, "tcp_v6_send_reset") == 0) + skarg_maybe_null = 1; + else + skarg_maybe_null = 0; + } else if (strcmp(prp->desc->prb, "connect-established") == 0) { + direction = NET_PROBE_INBOUND; + have_iphdr = 1; + skarg_maybe_null = 0; + } else if (strcmp(prp->desc->prb, "connect-refused") == 0) { + direction = NET_PROBE_INBOUND; + have_iphdr = 1; + skarg_maybe_null = 0; + skstate = BPF_TCP_SYN_SENT; + } else { + direction = NET_PROBE_OUTBOUND; + if (strcmp(uprp->desc->fun, "ip_send_unicast_reply") == 0) { + /* NULL sk in arg1 not arg2 (we dont want ctl_sk) */ + skarg = 1; + /* skb in arg2 not arg1 */ + skbarg = 2; + have_iphdr = 1; + /* tcp hdr in ip_reply_arg * */ + tcparg = 6; + skarg_maybe_null = 1; + } else if (strcmp(uprp->desc->fun, "ip_build_and_send_pkt") == 0) { + skarg = 1; + skbarg = 0; + have_iphdr = 0; + skarg_maybe_null = 1; + } else if (strcmp(prp->desc->prb, "connect-request") == 0) { + skstate = BPF_TCP_SYN_SENT; + have_iphdr = 0; + skarg_maybe_null = 0; + } else { + have_iphdr = 0; + skarg_maybe_null = 0; + } + } + /* + * We construct the tcp:::(receive,send) probe arguments as + * follows: + * args[0] = skb + * args[1] = sk + * args[2] = ip_hdr(skb) [if available] + * args[3] = sk [struct tcp_sock *] + * args[4] = tcp_hdr(skb) + * args[5] = sk->sk_state + * args[6] = sk->sk_state + * args[7] = NET_PROBE_INBOUND (0x1) | NET_PROBE_OUTBOUND (0x0) + */ + + /* first save sk to args[3]; this avoids overwriting it when we + * populate args[0,1] below. + */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(skarg))); + /* only allow NULL sk for ip_send_unicast_reply() */ + if (!skarg_maybe_null) + emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_6, 0, exitlbl)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(3), BPF_REG_6)); + + /* then save skb to args[0] */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(skbarg))); + emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_6, 0, exitlbl)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_6)); + + /* next save sk to args[1] now that we have skb in args[0] */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(3))); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_6)); + + /* + * ip_hdr(skb) = + * skb_network_header(skb) = (include/linux/ip.h) + * skb->head + skb->network_header (include/linux/skbuff.h) + */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(0))); + get_member(pcb, "struct sk_buff", BPF_REG_6, "head"); + if (have_iphdr) + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(2), BPF_REG_0)); + else + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(2), 0)); + + if (have_iphdr) { + get_member(pcb, "struct sk_buff", BPF_REG_6, "network_header"); + emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_7, DMST_ARG(2), BPF_REG_0)); + } + /* + * tcp_hdr(skb) = + * skb_transport_header(skb) = (include/linux/ip.h) + * skb->head + skb->transport_header (include/linux/skbuff.h) + */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(tcparg))); + if (tcparg) { + get_member(pcb, "struct kvec", BPF_REG_6, "iov_base"); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(4), BPF_REG_0)); + } else { + get_member(pcb, "struct sk_buff", BPF_REG_6, "head"); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(4), BPF_REG_0)); + get_member(pcb, "struct sk_buff", BPF_REG_6, "transport_header"); + emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_7, DMST_ARG(4), BPF_REG_0)); + } + + if (!skarg_maybe_null) { + /* save sk state */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(3))); + get_member(pcb, "struct sock_common", BPF_REG_6, "skc_state"); + /* ensure sk state - if specified - is what we expect */ + if (skstate) + emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, skstate, + exitlbl)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(5), BPF_REG_0)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(6), BPF_REG_0)); + } + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(7), direction)); + + return 0; +} + +dt_provimpl_t dt_tcp = { + .name = prvname, + .prog_type = BPF_PROG_TYPE_UNSPEC, + .populate = &populate, + .enable = &dt_sdt_enable, + .load_prog = &dt_bpf_prog_load, + .trampoline = &trampoline, + .probe_info = &dt_sdt_probe_info, + .destroy = &dt_sdt_destroy, +}; diff --git a/libdtrace/dt_provider.c b/libdtrace/dt_provider.c index 0c621197..798e67ee 100644 --- a/libdtrace/dt_provider.c +++ b/libdtrace/dt_provider.c @@ -41,6 +41,7 @@ const dt_provimpl_t *dt_providers[] = { &dt_sched, &dt_sdt, &dt_syscall, + &dt_tcp, &dt_uprobe, &dt_usdt, NULL diff --git a/libdtrace/dt_provider.h b/libdtrace/dt_provider.h index 59a8d62e..4db89b45 100644 --- a/libdtrace/dt_provider.h +++ b/libdtrace/dt_provider.h @@ -87,6 +87,7 @@ extern dt_provimpl_t dt_rawtp; extern dt_provimpl_t dt_sched; extern dt_provimpl_t dt_sdt; extern dt_provimpl_t dt_syscall; +extern dt_provimpl_t dt_tcp; extern dt_provimpl_t dt_uprobe; extern dt_provimpl_t dt_usdt; diff --git a/libdtrace/ip.d b/libdtrace/ip.d index f8b77f12..d59bb436 100644 --- a/libdtrace/ip.d +++ b/libdtrace/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/libdtrace/net.d b/libdtrace/net.d index 6ac34287..45b5cba3 100644 --- a/libdtrace/net.d +++ b/libdtrace/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/libdtrace/tcp.d b/libdtrace/tcp.d index 54e310cb..97c00191 100644 --- a/libdtrace/tcp.d +++ b/libdtrace/tcp.d @@ -60,7 +60,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,7 +111,7 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; @@ -164,41 +164,38 @@ translator tcpsinfo_t < struct tcp_sock *T > { ntohs(((struct sock *)T)->__sk_common.skc_num) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +226,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; -- 2.43.5 From alan.maguire at oracle.com Thu Jun 5 21:33:41 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Thu, 5 Jun 2025 22:33:41 +0100 Subject: [DTrace-devel] [RFC 2/2] dtrace: sync dlibs with tcp.d, ip.d and net.d changes In-Reply-To: <20250605213341.1410405-1-alan.maguire@oracle.com> References: <20250605213341.1410405-1-alan.maguire@oracle.com> Message-ID: <20250605213341.1410405-3-alan.maguire@oracle.com> As part of adding tcp provider tcp.d, ip.d and net.d were changed; sync the version-specific dlibs. Signed-off-by: Alan Maguire --- dlibs/aarch64/5.14/ip.d | 1 - dlibs/aarch64/5.14/net.d | 6 +++++- dlibs/aarch64/5.14/tcp.d | 43 +++++++++++++++++++++------------------- dlibs/aarch64/5.16/ip.d | 1 - dlibs/aarch64/5.16/net.d | 6 +++++- dlibs/aarch64/5.16/tcp.d | 43 +++++++++++++++++++++------------------- dlibs/aarch64/6.1/ip.d | 1 - dlibs/aarch64/6.1/net.d | 6 +++++- dlibs/aarch64/6.1/tcp.d | 43 +++++++++++++++++++++------------------- dlibs/aarch64/6.10/ip.d | 1 - dlibs/aarch64/6.10/net.d | 6 +++++- dlibs/aarch64/6.10/tcp.d | 43 +++++++++++++++++++++------------------- dlibs/x86_64/5.14/ip.d | 1 - dlibs/x86_64/5.14/net.d | 6 +++++- dlibs/x86_64/5.14/tcp.d | 43 +++++++++++++++++++++------------------- dlibs/x86_64/5.16/ip.d | 1 - dlibs/x86_64/5.16/net.d | 6 +++++- dlibs/x86_64/5.16/tcp.d | 43 +++++++++++++++++++++------------------- dlibs/x86_64/6.1/ip.d | 1 - dlibs/x86_64/6.1/net.d | 6 +++++- dlibs/x86_64/6.1/tcp.d | 43 +++++++++++++++++++++------------------- dlibs/x86_64/6.10/ip.d | 1 - dlibs/x86_64/6.10/net.d | 6 +++++- dlibs/x86_64/6.10/tcp.d | 43 +++++++++++++++++++++------------------- 24 files changed, 224 insertions(+), 176 deletions(-) diff --git a/dlibs/aarch64/5.14/ip.d b/dlibs/aarch64/5.14/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/aarch64/5.14/ip.d +++ b/dlibs/aarch64/5.14/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/aarch64/5.14/net.d b/dlibs/aarch64/5.14/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/aarch64/5.14/net.d +++ b/dlibs/aarch64/5.14/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/aarch64/5.14/tcp.d b/dlibs/aarch64/5.14/tcp.d index 54e310cb..97c00191 100644 --- a/dlibs/aarch64/5.14/tcp.d +++ b/dlibs/aarch64/5.14/tcp.d @@ -60,7 +60,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,7 +111,7 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; @@ -164,41 +164,38 @@ translator tcpsinfo_t < struct tcp_sock *T > { ntohs(((struct sock *)T)->__sk_common.skc_num) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +226,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/aarch64/5.16/ip.d b/dlibs/aarch64/5.16/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/aarch64/5.16/ip.d +++ b/dlibs/aarch64/5.16/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/aarch64/5.16/net.d b/dlibs/aarch64/5.16/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/aarch64/5.16/net.d +++ b/dlibs/aarch64/5.16/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/aarch64/5.16/tcp.d b/dlibs/aarch64/5.16/tcp.d index 54e310cb..97c00191 100644 --- a/dlibs/aarch64/5.16/tcp.d +++ b/dlibs/aarch64/5.16/tcp.d @@ -60,7 +60,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,7 +111,7 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; @@ -164,41 +164,38 @@ translator tcpsinfo_t < struct tcp_sock *T > { ntohs(((struct sock *)T)->__sk_common.skc_num) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +226,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/aarch64/6.1/ip.d b/dlibs/aarch64/6.1/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/aarch64/6.1/ip.d +++ b/dlibs/aarch64/6.1/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/aarch64/6.1/net.d b/dlibs/aarch64/6.1/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/aarch64/6.1/net.d +++ b/dlibs/aarch64/6.1/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/aarch64/6.1/tcp.d b/dlibs/aarch64/6.1/tcp.d index 54e310cb..97c00191 100644 --- a/dlibs/aarch64/6.1/tcp.d +++ b/dlibs/aarch64/6.1/tcp.d @@ -60,7 +60,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,7 +111,7 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; @@ -164,41 +164,38 @@ translator tcpsinfo_t < struct tcp_sock *T > { ntohs(((struct sock *)T)->__sk_common.skc_num) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +226,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/aarch64/6.10/ip.d b/dlibs/aarch64/6.10/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/aarch64/6.10/ip.d +++ b/dlibs/aarch64/6.10/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/aarch64/6.10/net.d b/dlibs/aarch64/6.10/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/aarch64/6.10/net.d +++ b/dlibs/aarch64/6.10/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/aarch64/6.10/tcp.d b/dlibs/aarch64/6.10/tcp.d index 54e310cb..97c00191 100644 --- a/dlibs/aarch64/6.10/tcp.d +++ b/dlibs/aarch64/6.10/tcp.d @@ -60,7 +60,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,7 +111,7 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; @@ -164,41 +164,38 @@ translator tcpsinfo_t < struct tcp_sock *T > { ntohs(((struct sock *)T)->__sk_common.skc_num) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +226,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/x86_64/5.14/ip.d b/dlibs/x86_64/5.14/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/x86_64/5.14/ip.d +++ b/dlibs/x86_64/5.14/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/x86_64/5.14/net.d b/dlibs/x86_64/5.14/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/x86_64/5.14/net.d +++ b/dlibs/x86_64/5.14/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/x86_64/5.14/tcp.d b/dlibs/x86_64/5.14/tcp.d index 54e310cb..97c00191 100644 --- a/dlibs/x86_64/5.14/tcp.d +++ b/dlibs/x86_64/5.14/tcp.d @@ -60,7 +60,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,7 +111,7 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; @@ -164,41 +164,38 @@ translator tcpsinfo_t < struct tcp_sock *T > { ntohs(((struct sock *)T)->__sk_common.skc_num) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +226,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/x86_64/5.16/ip.d b/dlibs/x86_64/5.16/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/x86_64/5.16/ip.d +++ b/dlibs/x86_64/5.16/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/x86_64/5.16/net.d b/dlibs/x86_64/5.16/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/x86_64/5.16/net.d +++ b/dlibs/x86_64/5.16/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/x86_64/5.16/tcp.d b/dlibs/x86_64/5.16/tcp.d index 54e310cb..97c00191 100644 --- a/dlibs/x86_64/5.16/tcp.d +++ b/dlibs/x86_64/5.16/tcp.d @@ -60,7 +60,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,7 +111,7 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; @@ -164,41 +164,38 @@ translator tcpsinfo_t < struct tcp_sock *T > { ntohs(((struct sock *)T)->__sk_common.skc_num) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +226,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/x86_64/6.1/ip.d b/dlibs/x86_64/6.1/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/x86_64/6.1/ip.d +++ b/dlibs/x86_64/6.1/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/x86_64/6.1/net.d b/dlibs/x86_64/6.1/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/x86_64/6.1/net.d +++ b/dlibs/x86_64/6.1/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/x86_64/6.1/tcp.d b/dlibs/x86_64/6.1/tcp.d index 54e310cb..97c00191 100644 --- a/dlibs/x86_64/6.1/tcp.d +++ b/dlibs/x86_64/6.1/tcp.d @@ -60,7 +60,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,7 +111,7 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; @@ -164,41 +164,38 @@ translator tcpsinfo_t < struct tcp_sock *T > { ntohs(((struct sock *)T)->__sk_common.skc_num) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +226,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/x86_64/6.10/ip.d b/dlibs/x86_64/6.10/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/x86_64/6.10/ip.d +++ b/dlibs/x86_64/6.10/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/x86_64/6.10/net.d b/dlibs/x86_64/6.10/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/x86_64/6.10/net.d +++ b/dlibs/x86_64/6.10/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/x86_64/6.10/tcp.d b/dlibs/x86_64/6.10/tcp.d index 54e310cb..97c00191 100644 --- a/dlibs/x86_64/6.10/tcp.d +++ b/dlibs/x86_64/6.10/tcp.d @@ -60,7 +60,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,7 +111,7 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; @@ -164,41 +164,38 @@ translator tcpsinfo_t < struct tcp_sock *T > { ntohs(((struct sock *)T)->__sk_common.skc_num) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +226,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; -- 2.43.5 From noreply at github.com Fri Jun 6 06:37:39 2025 From: noreply at github.com (euloh) Date: Thu, 05 Jun 2025 23:37:39 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] 62e2fc: dtprobed, usdt parser: add support for ELF notes-b... Message-ID: Branch: refs/heads/kvh/usdt-dev Home: https://github.com/oracle/dtrace-utils Commit: 62e2fc3ead5e8d39c14b10977986079bcb69cdbe https://github.com/oracle/dtrace-utils/commit/62e2fc3ead5e8d39c14b10977986079bcb69cdbe Author: Kris Van Hees Date: 2025-06-06 (Fri, 06 Jun 2025) Changed paths: M dtprobed/dof_stash.c M dtprobed/dof_stash.h M dtprobed/dtprobed.c M libcommon/Build M libcommon/usdt_parser.c M libcommon/usdt_parser.h M libcommon/usdt_parser_dof.c M libcommon/usdt_parser_host.c A libcommon/usdt_parser_notes.c Log Message: ----------- dtprobed, usdt parser: add support for ELF notes-based USDT Signed-off-by: Kris Van Hees Commit: a996f72b19a6e0d5ba98b6e6615225c63cf6ed2f https://github.com/oracle/dtrace-utils/commit/a996f72b19a6e0d5ba98b6e6615225c63cf6ed2f Author: Kris Van Hees Date: 2025-06-06 (Fri, 06 Jun 2025) Changed paths: M include/dtrace/pid.h M libdtrace/dt_cg.c M libdtrace/dt_cg.h M libdtrace/dt_pid.c M libdtrace/dt_prov_uprobe.c Log Message: ----------- usdt: implement tracing USDT probes specified in ELF notes Commit: 538929727a498407c1353eba8ed43b2b7386df98 https://github.com/oracle/dtrace-utils/commit/538929727a498407c1353eba8ed43b2b7386df98 Author: Kris Van Hees Date: 2025-06-06 (Fri, 06 Jun 2025) Changed paths: M libdtrace/drti.c M libdtrace/dt_dof.c M libdtrace/dt_impl.h M libdtrace/dt_link.c M libdtrace/dt_program.c M test/triggers/Build A test/triggers/usdt-tst-arg-const-prov.d A test/triggers/usdt-tst-arg-const.c A test/triggers/usdt-tst-arg-reg-prov.d A test/triggers/usdt-tst-arg-reg.c A test/triggers/usdt-tst-deref-decode-prov.d A test/triggers/usdt-tst-deref-decode.aarch64.c A test/triggers/usdt-tst-deref-decode.x86_64.c M test/unittest/options/tst.strip.sh A test/unittest/usdt/err.wrong-probe-argc-cc.sh A test/unittest/usdt/err.wrong-probe-argc-rt.sh A test/unittest/usdt/err.wrong-probe.sh A test/unittest/usdt/err.wrong-prov.sh A test/unittest/usdt/tst.arg-reg.d A test/unittest/usdt/tst.arg-reg.r R test/unittest/usdt/tst.badguess.sh R test/unittest/usdt/tst.badguess.x A test/unittest/usdt/tst.const.d A test/unittest/usdt/tst.const.r A test/unittest/usdt/tst.deref-decode.d R test/unittest/usdt/tst.guess32.sh R test/unittest/usdt/tst.guess32.x M test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p M test/utils/Build M test/utils/showUSDT.c M uts/common/sys/sdt.h A uts/common/sys/usdt.h A uts/common/sys/usdt_gennote.h A uts/common/sys/usdt_internal.h Log Message: ----------- link: implement USDT probe definitions in ELF notes Signed-off-by: Kris Van Hees Commit: 4984318b74f4b403af075b175cd8801c6abffc21 https://github.com/oracle/dtrace-utils/commit/4984318b74f4b403af075b175cd8801c6abffc21 Author: Kris Van Hees Date: 2025-06-06 (Fri, 06 Jun 2025) Changed paths: M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh Log Message: ----------- test: fix test for non-installed testing On a system without DTrace installed, cannot be found, causing this test to fail. Use test_cppflags to ensure the correct location is used in all cases. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: b2ab2b76fe091401c3b0b93438ba8c0ae91c5cf0 https://github.com/oracle/dtrace-utils/commit/b2ab2b76fe091401c3b0b93438ba8c0ae91c5cf0 Author: Eugene Loh Date: 2025-06-06 (Fri, 06 Jun 2025) Changed paths: M test/unittest/usdt/tst.pidprobes.sh Log Message: ----------- test: Adapt USDT PC search for USDT LTO changes To check USDT PCs, we looked at disassembly for characteristics that indicated USDT probes. With LTO, however, USDT instrumentation has changed. Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. Note that tst.pidargs.sh and tst.pidargmap.sh depend on tst.pidprobes.sh. Therefore, those tests also benefit from this change. They do not yet pass, however, since index 0 for args[] is said to be out of range. Signed-off-by: Eugene Loh Compare: https://github.com/oracle/dtrace-utils/compare/2ac3202150dd...b2ab2b76fe09 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 Sat Jun 7 05:52:26 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 7 Jun 2025 01:52:26 -0400 Subject: [DTrace-devel] [PATCH] test: Adapt USDT PC search for USDT LTO changes In-Reply-To: <20250603042146.11894-1-eugene.loh@oracle.com> References: <20250603042146.11894-1-eugene.loh@oracle.com> Message-ID: Reviewed-by: Kris Van Hees On Tue, Jun 03, 2025 at 12:21:46AM -0400, eugene.loh at oracle.com wrote: > From: Eugene Loh > > To check USDT PCs, we looked at disassembly for characteristics that > indicated USDT probes. > > With LTO, however, USDT instrumentation has changed. > > Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. > > Note that tst.pidargs.sh and tst.pidargmap.sh depend on > tst.pidprobes.sh. Therefore, those tests also benefit from this change. > They do not yet pass, however, since index 0 for args[] is said to be > out of range. > > Signed-off-by: Eugene Loh > --- > libdtrace/dt_prov_uprobe.c | 2 +- > test/unittest/usdt/tst.pidprobes.sh | 114 ++++++++++------------------ > 2 files changed, 40 insertions(+), 76 deletions(-) > > diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c > index 26f513fe..aecb07d5 100644 > --- a/libdtrace/dt_prov_uprobe.c > +++ b/libdtrace/dt_prov_uprobe.c > @@ -901,7 +901,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, > pd.fun = ""; > pd.prb = prb; > > -fprintf(stderr, "Underlying probe %s:%s:%s:%s @ %lx\n", psp->pps_prv, psp->pps_mod, psp->pps_fn, psp->pps_prb, psp->pps_off); > +// fprintf(stderr, "Underlying probe %s:%s:%s:%s @ %lx\n", psp->pps_prv, psp->pps_mod, psp->pps_fn, psp->pps_prb, psp->pps_off); > 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); > uprp = dt_probe_lookup(dtp, &pd); > diff --git a/test/unittest/usdt/tst.pidprobes.sh b/test/unittest/usdt/tst.pidprobes.sh > index 0c75d796..6a1fa984 100755 > --- a/test/unittest/usdt/tst.pidprobes.sh > +++ b/test/unittest/usdt/tst.pidprobes.sh > @@ -19,6 +19,7 @@ mapping=${3:-} > > # Set up test directory. > > +d=`pwd` > DIRNAME=$tmpdir/pidprobes.$$.$RANDOM > mkdir -p $DIRNAME > cd $DIRNAME > @@ -74,9 +75,6 @@ if [ $? -ne 0 ]; then > echo "failed to compile test" >&2 > exit 1 > fi > -if [[ `uname -m` = "aarch64" ]]; then > - objdump -d main.o > disasm_foo.txt.before > -fi > $dtrace $dt_flags -G -64 -s prov.d main.o > if [ $? -ne 0 ]; then > echo "failed to create DOF" >&2 > @@ -183,84 +181,50 @@ if [ `awk 'NF != 0 { print $1 }' dtrace.out | uniq | wc -l` -ne 1 ]; then > fi > pid=`awk 'NF != 0 { print $1 }' dtrace.out | uniq` > > -# From the disassembly, get the PCs for USDT probes. > -# Check libdtrace/dt_link.c's arch-dependent dt_modtext() to see > -# what sequence of instructions signal a USDT probe. > - > -if [[ `uname -m` = "x86_64" ]]; then > - > - # It is the first of five nop instructions in a row. > - # So track pc[-6], pc[-5], pc[-4], pc[-3], pc[-2], pc[-1], pc[0] > - # as well as whether they are nop. > - > - usdt_pcs_all=`awk ' > - BEGIN { > - pc6 = -1; is_nop6 = 0; > - pc5 = -1; is_nop5 = 0; > - pc4 = -1; is_nop4 = 0; > - pc3 = -1; is_nop3 = 0; > - pc2 = -1; is_nop2 = 0; > - pc1 = -1; is_nop1 = 0; > +# From showUSDT output, get the PCs for USDT probes. We look for output like: > +# Note usdt, type N: > +# Offset 0xoffset > +# Function Offset 0xfoffset > +# Probe pyramid::foo:entry > +$d/test/utils/showUSDT main | awk ' > +/^ *Note usdt, type / { > + getline; > + if (!match($0, /^ *Offset *0x[0-9a-f]* *$/)) { > + print "ERROR: expect Offset"; > + exit(1); > } > - { > - # pc0 is current instruction > - pc0 = strtonum("0x"$1); > - > - # decide whether it is a nop > - is_nop0 = 0; > - if (NF == 3 && > - $2 == "90" && > - $3 == "nop") > - is_nop0 = 1; > - > - # report if pc[-5] is a USDT instruction > - if (is_nop6 == 0 && > - is_nop5 == 1 && > - is_nop4 == 1 && > - is_nop3 == 1 && > - is_nop2 == 1 && > - is_nop1 == 1 && > - is_nop0 == 0) > - print pc5; > - > - # prepare advance to next instruction > - pc6 = pc5; is_nop6 = is_nop5; > - pc5 = pc4; is_nop5 = is_nop4; > - pc4 = pc3; is_nop4 = is_nop3; > - pc3 = pc2; is_nop3 = is_nop2; > - pc2 = pc1; is_nop2 = is_nop1; > - pc1 = pc0; is_nop1 = is_nop0; > - }' disasm_foo.txt` > - > - # We expect 4 USDT probes (2 USDT and 2 is-enabled). > - if [ `echo $usdt_pcs_all | awk '{print NF}'` -ne 4 ]; then > - echo ERROR: expected 4 USDT probes but got $usdt_pcs_all > - cat disasm_foo.txt > - exit 1 > - fi > + off = strtonum($2); > > - # Separate them into regular and is-enabled PCs. > - # We assume they alternate. > - usdt_pcs=`echo $usdt_pcs_all | awk '{ print $1, $3 }'` > - usdt_pcs_isenabled=`echo $usdt_pcs_all | awk '{ print $2, $4 }'` > + getline; > + if (!match($0, /^ *Function Offset *0x[0-9a-f]* *$/)) { > + print "ERROR: expect Function Offset"; > + exit(1); > + } > > -elif [[ `uname -m` = "aarch64" ]]; then > + getline; > + if (!match($0, /^ *Probe pyramid::foo:entry/)) { > + print "ERROR: expect Probe pyramid::foo:entry"; > + exit(1); > + } > > - # The initial compilation of foo() makes it obvious where the > - # USDT probes are. We just have to add the function offset in. > - usdt_pcs=`awk '/<__dtrace_pyramid___entry>/ { print strtonum("0x"$1) + '$pc0' }' disasm_foo.txt.before` > - usdt_pcs_isenabled=`awk '/<__dtraceenabled_pyramid___entry>/ { print strtonum("0x"$1) + '$pc0' }' disasm_foo.txt.before` > + print off, $0; > +} ' > usdt_pcs.txt > +if [ $? -ne 0 ]; then > + echo ERROR: showUSDT output to awk > + $d/test/utils/showUSDT main > + exit 1 > +fi > +usdt_pcs=`awk '!/is-enabled/ { sub("0x", ""); print $1}' usdt_pcs.txt` > +usdt_pcs_isenabled=`awk '/is-enabled/ { sub("0x", ""); print $1}' usdt_pcs.txt` > > - # We expect 4 USDT probes (2 USDT and 2 is-enabled). > - if [ `echo $usdt_pcs | awk '{print NF}'` -ne 2 -o \ > - `echo $usdt_pcs_isenabled | awk '{print NF}'` -ne 2 ]; then > - echo ERROR: expected 4 USDT probes but got $usdt_pcs and $usdt_pcs_isenabled > - cat disasm_foo.txt.before > - exit 1 > - fi > +# We expect 2 USDT probes plus 2 is-enabled. > > -else > - echo ERROR unrecognized machine hardware name > +if [ `echo $usdt_pcs | awk '{print NF}'` -ne 2 ]; then > + echo ERROR: expected 2 USDT regular probes but got $usdt_pcs > + exit 1 > +fi > +if [ `echo $usdt_pcs_isenabled | awk '{print NF}'` -ne 2 ]; then > + echo ERROR: expected 2 USDT is-enabled probes but got $usdt_pcs_isenabled > exit 1 > fi > > -- > 2.43.5 > From noreply at github.com Sat Jun 7 06:09:59 2025 From: noreply at github.com (euloh) Date: Fri, 06 Jun 2025 23:09:59 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] cf3da5: provider: fix registering fbt and rawfbt twice Message-ID: Branch: refs/heads/kvh/usdt-dev Home: https://github.com/oracle/dtrace-utils Commit: cf3da5d629c5ec7431ebbde1d589ee77aa404b57 https://github.com/oracle/dtrace-utils/commit/cf3da5d629c5ec7431ebbde1d589ee77aa404b57 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libdtrace/dt_provider.c M libdtrace/dt_provider.h Log Message: ----------- provider: fix registering fbt and rawfbt twice Now that rawfbt has been integrated into the fbt provider, it no longer needs to be in the list of providers to call populate() in. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 671679ca7109b03fb9fd0d75cad29d50d9ca6a9b https://github.com/oracle/dtrace-utils/commit/671679ca7109b03fb9fd0d75cad29d50d9ca6a9b Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libdtrace/dt_provider.c Log Message: ----------- providers: loop through all providers for discovery The discovery of probes was tied to the static list of providers that are called on init. It should iterate over all providers that are in fact registered, i.e. the dt_provs hash. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: a717b347fd93f5463ff72d6b7a968d013d00a4cf https://github.com/oracle/dtrace-utils/commit/a717b347fd93f5463ff72d6b7a968d013d00a4cf Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libdtrace/dt_open.c M libdtrace/dt_version.h Log Message: ----------- Only include dt_git_version.h where needed Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 8f650c85424719ec60f5866361958f289f5f5cab https://github.com/oracle/dtrace-utils/commit/8f650c85424719ec60f5866361958f289f5f5cab Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libcommon/dof_parser.c Log Message: ----------- dof_parser: remove pointless comment Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 54213ccfaff8e209d8b61ca9d4ffd40d693942c7 https://github.com/oracle/dtrace-utils/commit/54213ccfaff8e209d8b61ca9d4ffd40d693942c7 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dtprobed.c M libcommon/dof_parser.c M libcommon/dof_parser.h Log Message: ----------- dof_parser: restructure the dof_copyin*() code All logic for reading data from the DOF parser pipe is now consolidated in dof_copyin(). Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 65d56b1c713ad22857056604c7ec9dfc792ca3f5 https://github.com/oracle/dtrace-utils/commit/65d56b1c713ad22857056604c7ec9dfc792ca3f5 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dof_stash.c M dtprobed/dof_stash.h M dtprobed/dtprobed.c M libcommon/Build R libcommon/dof_parser.c R libcommon/dof_parser.h R libcommon/dof_parser_host.c A libcommon/usdt_parser.c A libcommon/usdt_parser.h A libcommon/usdt_parser_dof.c A libcommon/usdt_parser_host.c M libdtrace/dt_pid.c Log Message: ----------- dof_parser: generic parser framework to support multiple parsers To prepare for non-DOF section based USDT probe definitions, the data passed from dtprobed to the USDT data parser is more generic. The dof_helper_t structure is passed first, followed by a block count, and that number of data blocks, passed as a size followed by the content. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: b90f5b95fed57cb0f49aed7eef26cad8e0c09d6d https://github.com/oracle/dtrace-utils/commit/b90f5b95fed57cb0f49aed7eef26cad8e0c09d6d Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dtprobed.c Log Message: ----------- dtprobed: fix probe name debug output Debug output while reading dof_parsed_t structures was printing the probe names as provider->provider.name and probe->probe.name, but probe.name is a 0-separated concatenation of the probe name elements. It only printed the module name. Corrected to print the full probe name. Also moved it to the proper place (when a new probe is read rather than for every tracepoint). Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Reviewed-by: Eugene Loh Commit: 3350ae4fc291cc2f8d021158805769e952ddebed https://github.com/oracle/dtrace-utils/commit/3350ae4fc291cc2f8d021158805769e952ddebed Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libcommon/Build A libcommon/dt_htab.c A libcommon/dt_htab.h M libdtrace/Build M libdtrace/dt_consume.c R libdtrace/dt_htab.c R libdtrace/dt_htab.h M libdtrace/dt_kernel_module.c M libdtrace/dt_module.c M libdtrace/dt_open.c M libdtrace/dt_probe.c M libdtrace/dt_provider.c M libdtrace/dt_symtab.c Log Message: ----------- htab: move htab handling to libcommon Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 3530b90b3486e5de33773390f8cf1bf9546fe9c3 https://github.com/oracle/dtrace-utils/commit/3530b90b3486e5de33773390f8cf1bf9546fe9c3 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libcommon/dt_htab.c M libcommon/dt_htab.h M libdtrace/dt_string.c M libdtrace/dt_string.h Log Message: ----------- htab: move str2hval() to dt_htab Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 2cbb15865c8f07dce97e3a673886c812cd62e6c4 https://github.com/oracle/dtrace-utils/commit/2cbb15865c8f07dce97e3a673886c812cd62e6c4 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dtprobed.c Log Message: ----------- dtprobed: make sure that retry one time means exactly that Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 22b24012109bf79522bc0f2e2d2a9c5b0136135f https://github.com/oracle/dtrace-utils/commit/22b24012109bf79522bc0f2e2d2a9c5b0136135f Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M include/dtrace/ioctl.h Log Message: ----------- usdt: add HASUSDT to the helper ioctl interface Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: f8a064e7b532458b4154150e1537dc3de6673443 https://github.com/oracle/dtrace-utils/commit/f8a064e7b532458b4154150e1537dc3de6673443 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dof_stash.c M dtprobed/dof_stash.h M dtprobed/dtprobed.c M libcommon/Build M libcommon/usdt_parser.c M libcommon/usdt_parser.h M libcommon/usdt_parser_dof.c M libcommon/usdt_parser_host.c A libcommon/usdt_parser_notes.c A uts/common/sys/usdt_note_defs.h Log Message: ----------- dtprobed, usdt parser: add support for ELF notes-based USDT Signed-off-by: Kris Van Hees Commit: a74ebed12cfaa652a83e2562861d31a526df1b37 https://github.com/oracle/dtrace-utils/commit/a74ebed12cfaa652a83e2562861d31a526df1b37 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M include/dtrace/pid.h M libdtrace/dt_cg.c M libdtrace/dt_cg.h M libdtrace/dt_pid.c M libdtrace/dt_prov_uprobe.c Log Message: ----------- usdt: implement tracing USDT probes specified in ELF notes Commit: 90883ed9c9e31e80344474a51367a0f371540730 https://github.com/oracle/dtrace-utils/commit/90883ed9c9e31e80344474a51367a0f371540730 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libdtrace/drti.c M libdtrace/dt_dof.c M libdtrace/dt_impl.h M libdtrace/dt_link.c M libdtrace/dt_program.c M test/triggers/Build A test/triggers/usdt-tst-arg-const-prov.d A test/triggers/usdt-tst-arg-const.c A test/triggers/usdt-tst-arg-reg-prov.d A test/triggers/usdt-tst-arg-reg.c A test/triggers/usdt-tst-deref-decode-prov.d A test/triggers/usdt-tst-deref-decode.aarch64.c A test/triggers/usdt-tst-deref-decode.x86_64.c M test/unittest/options/tst.strip.sh A test/unittest/usdt/err.wrong-probe-argc-cc.sh A test/unittest/usdt/err.wrong-probe-argc-rt.sh A test/unittest/usdt/err.wrong-probe.sh A test/unittest/usdt/err.wrong-prov.sh A test/unittest/usdt/tst.arg-reg.d A test/unittest/usdt/tst.arg-reg.r R test/unittest/usdt/tst.badguess.sh R test/unittest/usdt/tst.badguess.x A test/unittest/usdt/tst.const.d A test/unittest/usdt/tst.const.r A test/unittest/usdt/tst.deref-decode.d R test/unittest/usdt/tst.guess32.sh R test/unittest/usdt/tst.guess32.x M test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p M test/utils/Build M test/utils/showUSDT.c M uts/common/sys/sdt.h A uts/common/sys/usdt.h A uts/common/sys/usdt_gennote.h A uts/common/sys/usdt_internal.h Log Message: ----------- link: implement USDT probe definitions in ELF notes Signed-off-by: Kris Van Hees Commit: 4a0f64f347db7c3a2992bef3c66cc785b6d9937d https://github.com/oracle/dtrace-utils/commit/4a0f64f347db7c3a2992bef3c66cc785b6d9937d Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh Log Message: ----------- test: fix test for non-installed testing On a system without DTrace installed, cannot be found, causing this test to fail. Use test_cppflags to ensure the correct location is used in all cases. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: d1df03dc53af46abf36b22385030b3c6b5c55547 https://github.com/oracle/dtrace-utils/commit/d1df03dc53af46abf36b22385030b3c6b5c55547 Author: Eugene Loh Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M test/unittest/usdt/tst.pidprobes.sh Log Message: ----------- test: Adapt USDT PC search for USDT LTO changes To check USDT PCs, we looked at disassembly for characteristics that indicated USDT probes. With LTO, however, USDT instrumentation has changed. Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. Note that tst.pidargs.sh and tst.pidargmap.sh depend on tst.pidprobes.sh. Therefore, those tests also benefit from this change. They do not yet pass, however, since index 0 for args[] is said to be out of range. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/b2ab2b76fe09...d1df03dc53af 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 Sat Jun 7 06:14:56 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:14:56 -0400 Subject: [DTrace-devel] [PATCH 02/17] provider: fix registering fbt and rawfbt twice Message-ID: Now that rawfbt has been integrated into the fbt provider, it no longer needs to be in the list of providers to call populate() in. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh --- libdtrace/dt_provider.c | 1 - libdtrace/dt_provider.h | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libdtrace/dt_provider.c b/libdtrace/dt_provider.c index 0c621197..1e2e844e 100644 --- a/libdtrace/dt_provider.c +++ b/libdtrace/dt_provider.c @@ -36,7 +36,6 @@ const dt_provimpl_t *dt_providers[] = { &dt_lockstat, &dt_proc, &dt_profile, - &dt_rawfbt, &dt_rawtp, &dt_sched, &dt_sdt, diff --git a/libdtrace/dt_provider.h b/libdtrace/dt_provider.h index 59a8d62e..2a3bba80 100644 --- a/libdtrace/dt_provider.h +++ b/libdtrace/dt_provider.h @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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. */ @@ -82,7 +82,6 @@ extern dt_provimpl_t dt_ip; extern dt_provimpl_t dt_lockstat; extern dt_provimpl_t dt_proc; extern dt_provimpl_t dt_profile; -extern dt_provimpl_t dt_rawfbt; extern dt_provimpl_t dt_rawtp; extern dt_provimpl_t dt_sched; extern dt_provimpl_t dt_sdt; -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:14:57 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:14:57 -0400 Subject: [DTrace-devel] [PATCH 03/17] providers: loop through all providers for discovery Message-ID: The discovery of probes was tied to the static list of providers that are called on init. It should iterate over all providers that are in fact registered, i.e. the dt_provs hash. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh --- libdtrace/dt_provider.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libdtrace/dt_provider.c b/libdtrace/dt_provider.c index 1e2e844e..06f0b039 100644 --- a/libdtrace/dt_provider.c +++ b/libdtrace/dt_provider.c @@ -176,11 +176,13 @@ dt_provider_xref(dtrace_hdl_t *dtp, dt_provider_t *pvp, id_t id) int dt_provider_discover(dtrace_hdl_t *dtp) { - int i, prid = dtp->dt_probe_id; + int prid = dtp->dt_probe_id; + dt_htab_next_t *it = NULL; + dt_provider_t *pvp; /* Discover new probes. */ - for (i = 0; dt_providers[i]; i++) { - if (dt_providers[i]->discover && dt_providers[i]->discover(dtp) < 0) + while ((pvp = dt_htab_next(dtp->dt_provs, &it)) != NULL) { + if (pvp->impl->discover && pvp->impl->discover(dtp) < 0) return -1; /* errno is already set */ } -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:14:58 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:14:58 -0400 Subject: [DTrace-devel] [PATCH 04/17] Only include dt_git_version.h where needed Message-ID: Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh --- libdtrace/dt_open.c | 2 ++ libdtrace/dt_version.h | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c index 51c056b2..0bda3504 100644 --- a/libdtrace/dt_open.c +++ b/libdtrace/dt_open.c @@ -42,6 +42,8 @@ #include #include +#include + const dt_version_t _dtrace_versions[] = { DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */ DT_VERS_1_1, /* D API 1.1.0 Solaris Express 6/05 */ diff --git a/libdtrace/dt_version.h b/libdtrace/dt_version.h index 3fd1b3d1..29094587 100644 --- a/libdtrace/dt_version.h +++ b/libdtrace/dt_version.h @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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. */ @@ -13,7 +13,6 @@ extern "C" { #endif #include -#include /* * Stability definitions -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:14:55 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:14:55 -0400 Subject: [DTrace-devel] [PATCH 01/17] test: allow overriding CC, OBJCOPY, OBJDUMP, NM, ... Message-ID: Bug: https://github.com/oracle/dtrace-utils/issues/75 Signed-off-by: Sam James Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees --- runtest.sh | 5 +++++ .../expensive/locking/tst.DestructionDoubleUnlock.sh | 3 +-- test/internals/headers/tst.header-endianness.sh | 3 +-- test/stress/options/tst.cpu-syscall.sh | 4 ++-- test/unittest/aggs/tst.aggmod_full2.sh | 3 +-- test/unittest/arrays/tst.uregsarray-check.sh | 3 +-- test/unittest/bitfields/tst.bitfield-offset.x | 8 ++++---- test/unittest/builtinvar/tst.errno3.sh | 3 +-- test/unittest/builtinvar/tst.tid_pid.sh | 1 - test/unittest/dtrace-util/tst.ListProbesArgsUSDT.sh | 3 +-- test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh | 3 +-- .../unittest/dtrace-util/tst.ListProbesModuleUSDT.sh | 3 +-- test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh | 3 +-- .../dtrace-util/tst.ListProbesProviderUSDT.sh | 3 +-- test/unittest/fbtprovider/tst.entryargs2.sh | 1 - test/unittest/funcs/copyout/tst.copyout.sh | 4 ++-- test/unittest/funcs/copyoutstr/tst.copyoutstr.sh | 4 ++-- test/unittest/misc/tst.include.sh | 3 +-- test/unittest/options/tst.cpu-syscall.sh | 4 ++-- test/unittest/options/tst.ctypes.sh | 8 ++++---- test/unittest/options/tst.dtypes.sh | 8 ++++---- test/unittest/options/tst.linktype.sh | 5 ++--- test/unittest/options/tst.strip.sh | 5 ++--- test/unittest/pid/tst.dash.sh | 4 ++-- test/unittest/pid/tst.offsets.sh | 6 +++--- test/unittest/pid/tst.provregex1.sh | 6 +++--- test/unittest/pid/tst.provregex2.sh | 10 +++++----- test/unittest/pid/tst.provregex3.sh | 6 +++--- test/unittest/pid/tst.provregex4.sh | 10 +++++----- test/unittest/usdt/tst.allargs.sh | 3 +-- test/unittest/usdt/tst.badguess.sh | 3 +-- test/unittest/usdt/tst.badguess.x | 2 +- test/unittest/usdt/tst.dlclose1.sh | 3 +-- test/unittest/usdt/tst.dlclose2.sh | 3 +-- test/unittest/usdt/tst.dlclose3.sh | 3 +-- test/unittest/usdt/tst.dlclose4.sh | 3 +-- test/unittest/usdt/tst.eliminate.sh | 7 +++---- test/unittest/usdt/tst.enable_pid.sh | 7 +++---- test/unittest/usdt/tst.enabled.sh | 3 +-- test/unittest/usdt/tst.enabled2.sh | 3 +-- test/unittest/usdt/tst.entryreturn.sh | 3 +-- test/unittest/usdt/tst.exec-dof-replacement.sh | 3 +-- test/unittest/usdt/tst.execstack.sh | 5 +---- test/unittest/usdt/tst.fork.sh | 3 +-- test/unittest/usdt/tst.guess32.sh | 3 +-- test/unittest/usdt/tst.guess64.sh | 3 +-- test/unittest/usdt/tst.header.sh | 3 +-- test/unittest/usdt/tst.lingering.sh | 3 +-- test/unittest/usdt/tst.link-idempotence.sh | 3 +-- test/unittest/usdt/tst.linkpriv.sh | 3 +-- test/unittest/usdt/tst.linkunpriv.sh | 3 +-- test/unittest/usdt/tst.manyprobes.sh | 3 +-- test/unittest/usdt/tst.manyprocs.sh | 3 +-- test/unittest/usdt/tst.multiple.sh | 3 +-- test/unittest/usdt/tst.multiprov-dupprobe-shlibs.sh | 3 +-- test/unittest/usdt/tst.multitrace.sh | 3 +-- test/unittest/usdt/tst.nusdtprobes.sh | 6 +++--- test/unittest/usdt/tst.onlyenabled.sh | 3 +-- test/unittest/usdt/tst.pidprobes.sh | 12 ++++++------ test/unittest/usdt/tst.pie.sh | 3 +-- test/unittest/usdt/tst.reeval.sh | 3 +-- test/unittest/usdt/tst.static.sh | 3 +-- test/unittest/usdt/tst.static2.sh | 3 +-- test/unittest/usdt/tst.user.sh | 3 +-- test/utils/workload_analyze_loop.sh | 4 ++-- 65 files changed, 109 insertions(+), 153 deletions(-) diff --git a/runtest.sh b/runtest.sh index 15bd78fb..156e7dec 100755 --- a/runtest.sh +++ b/runtest.sh @@ -653,6 +653,11 @@ load_modules # Export some variables so triggers and .sh scripts can get at them. export _test _pid dt_flags +export CC=${CC:-/usr/bin/gcc} +export NM=${NM:-/usr/bin/nm} +export OBJCOPY=${OBJCOPY:-/usr/bin/objcopy} +export OBJDUMP=${OBJDUMP:-/usr/bin/objdump} +export READELF=${READELF:-/usr/bin/readelf} # Arrange to do (relatively expensive) mutex debugging. export DTRACE_OPT_DEBUGASSERT="mutexes" diff --git a/test/expensive/locking/tst.DestructionDoubleUnlock.sh b/test/expensive/locking/tst.DestructionDoubleUnlock.sh index c9b9eadc..b7118642 100755 --- a/test/expensive/locking/tst.DestructionDoubleUnlock.sh +++ b/test/expensive/locking/tst.DestructionDoubleUnlock.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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. # @@ -28,7 +28,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/destruction-double-unlock.$$.$RANDOM" diff --git a/test/internals/headers/tst.header-endianness.sh b/test/internals/headers/tst.header-endianness.sh index e45cc597..227da854 100755 --- a/test/internals/headers/tst.header-endianness.sh +++ b/test/internals/headers/tst.header-endianness.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 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. # @@ -10,7 +10,6 @@ set -e dtrace=$1 -CC=/usr/bin/gcc OLDDIRNAME=${PWD} CFLAGS="-I${OLDDIRNAME}/include -I${OLDDIRNAME}/uts/common" diff --git a/test/stress/options/tst.cpu-syscall.sh b/test/stress/options/tst.cpu-syscall.sh index 6fb09d48..3f6f2f48 100755 --- a/test/stress/options/tst.cpu-syscall.sh +++ b/test/stress/options/tst.cpu-syscall.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. # @@ -91,7 +91,7 @@ int main(int c, char **v) { } EOF -gcc main.c +$CC main.c if [ $? -ne 0 ]; then echo ERROR compilation failed exit 1 diff --git a/test/unittest/aggs/tst.aggmod_full2.sh b/test/unittest/aggs/tst.aggmod_full2.sh index 66cfc002..b87d6ba6 100755 --- a/test/unittest/aggs/tst.aggmod_full2.sh +++ b/test/unittest/aggs/tst.aggmod_full2.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 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. # @@ -17,7 +17,6 @@ ## dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/aggs-aggmod_full2.$$.$RANDOM" diff --git a/test/unittest/arrays/tst.uregsarray-check.sh b/test/unittest/arrays/tst.uregsarray-check.sh index f55d36d0..4f1aabaa 100755 --- a/test/unittest/arrays/tst.uregsarray-check.sh +++ b/test/unittest/arrays/tst.uregsarray-check.sh @@ -1,13 +1,12 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 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 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/arrays-uregsarray-check.$$.$RANDOM" diff --git a/test/unittest/bitfields/tst.bitfield-offset.x b/test/unittest/bitfields/tst.bitfield-offset.x index ae57c2b5..1f328c23 100755 --- a/test/unittest/bitfields/tst.bitfield-offset.x +++ b/test/unittest/bitfields/tst.bitfield-offset.x @@ -12,8 +12,8 @@ # skip the test, since we can't possibly tell what it was # generated by. -if ! objdump --ctf=.ctf --ctf-parent=shared_ctf /bin/true > /dev/null 2>&1 && \ - LANG=C objdump --ctf=.ctf --ctf-parent=shared_ctf /bin/true 2>&1 | \ +if ! ${OBJDUMP} --ctf=.ctf --ctf-parent=shared_ctf /bin/true > /dev/null 2>&1 && \ + LANG=C ${OBJDUMP} --ctf=.ctf --ctf-parent=shared_ctf /bin/true 2>&1 | \ grep 'unrecognized option' > /dev/null 2>&1; then exit 2 fi @@ -21,7 +21,7 @@ fi ctfa=$tmpdir/vmlinux.ctfa trap "rm -f $ctfa" EXIT ERR -objcopy --add-section=.ctf=/lib/modules/$(uname -r)/kernel/vmlinux.ctfa /bin/true $ctfa +${OBJCOPY} --add-section=.ctf=/lib/modules/$(uname -r)/kernel/vmlinux.ctfa /bin/true $ctfa -objdump --ctf=.ctf --ctf-parent=shared_ctf $ctfa |\ +${OBJDUMP} --ctf=.ctf --ctf-parent=shared_ctf $ctfa |\ gawk '/Version: 3/ { exit 1; } /Version: / { exit 0; }' diff --git a/test/unittest/builtinvar/tst.errno3.sh b/test/unittest/builtinvar/tst.errno3.sh index 7546152f..d1bcde39 100755 --- a/test/unittest/builtinvar/tst.errno3.sh +++ b/test/unittest/builtinvar/tst.errno3.sh @@ -1,13 +1,12 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2021, 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. # dtrace=$1 -CC=/usr/bin/gcc DIRNAME="$tmpdir/builtinvar-errno3.$$.$RANDOM" mkdir -p $DIRNAME diff --git a/test/unittest/builtinvar/tst.tid_pid.sh b/test/unittest/builtinvar/tst.tid_pid.sh index 7ff0227f..e367411d 100755 --- a/test/unittest/builtinvar/tst.tid_pid.sh +++ b/test/unittest/builtinvar/tst.tid_pid.sh @@ -7,7 +7,6 @@ # dtrace=$1 -CC=/usr/bin/gcc DIRNAME="$tmpdir/builtinvar-tid_pid.$$.$RANDOM" mkdir -p $DIRNAME diff --git a/test/unittest/dtrace-util/tst.ListProbesArgsUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesArgsUSDT.sh index 737f2cc8..945d2188 100755 --- a/test/unittest/dtrace-util/tst.ListProbesArgsUSDT.sh +++ b/test/unittest/dtrace-util/tst.ListProbesArgsUSDT.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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. @@ -20,7 +20,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/list-probes-args-usdt.$$.$RANDOM" diff --git a/test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh index f8083f2c..e7af9da9 100755 --- a/test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh +++ b/test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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. # @@ -22,7 +22,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/list-probes-func-usdt.$$.$RANDOM" diff --git a/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh index dc6cb100..f66d6cbd 100755 --- a/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh +++ b/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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. # @@ -22,7 +22,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/list-probes-module-usdt.$$.$RANDOM" diff --git a/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh index 59b8dca5..9f6ca8ba 100755 --- a/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh +++ b/test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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. # @@ -22,7 +22,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/list-probes-name-usdt.$$.$RANDOM" diff --git a/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh index 64fc185d..be6d87be 100755 --- a/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh +++ b/test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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. # @@ -22,7 +22,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/list-probes-provider-usdt.$$.$RANDOM" diff --git a/test/unittest/fbtprovider/tst.entryargs2.sh b/test/unittest/fbtprovider/tst.entryargs2.sh index f5b435f5..4485d33a 100755 --- a/test/unittest/fbtprovider/tst.entryargs2.sh +++ b/test/unittest/fbtprovider/tst.entryargs2.sh @@ -9,7 +9,6 @@ # dtrace=$1 -CC=${CC:-/usr/bin/gcc} # Set up test directory. diff --git a/test/unittest/funcs/copyout/tst.copyout.sh b/test/unittest/funcs/copyout/tst.copyout.sh index 748b138b..9553938b 100755 --- a/test/unittest/funcs/copyout/tst.copyout.sh +++ b/test/unittest/funcs/copyout/tst.copyout.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 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. @@ -31,7 +31,7 @@ int main(int c, char **v) { } EOF -gcc main.c +$CC main.c if [ $? -ne 0 ]; then echo "compilation error" exit 1 diff --git a/test/unittest/funcs/copyoutstr/tst.copyoutstr.sh b/test/unittest/funcs/copyoutstr/tst.copyoutstr.sh index d98897fc..284478b0 100755 --- a/test/unittest/funcs/copyoutstr/tst.copyoutstr.sh +++ b/test/unittest/funcs/copyoutstr/tst.copyoutstr.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 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. @@ -42,7 +42,7 @@ int main(int c, char **v) { } EOF -gcc main.c +$CC main.c if [ $? -ne 0 ]; then echo "compilation error" exit 1 diff --git a/test/unittest/misc/tst.include.sh b/test/unittest/misc/tst.include.sh index 9d9989a3..4cdacfe9 100755 --- a/test/unittest/misc/tst.include.sh +++ b/test/unittest/misc/tst.include.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 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. # @@ -13,7 +13,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIR="$tmpdir/misc-include.$$.$RANDOM" diff --git a/test/unittest/options/tst.cpu-syscall.sh b/test/unittest/options/tst.cpu-syscall.sh index 401839d5..4fb58c35 100755 --- a/test/unittest/options/tst.cpu-syscall.sh +++ b/test/unittest/options/tst.cpu-syscall.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. # @@ -91,7 +91,7 @@ int main(int c, char **v) { } EOF -gcc main.c +$CC main.c if [ $? -ne 0 ]; then echo ERROR compilation failed exit 1 diff --git a/test/unittest/options/tst.ctypes.sh b/test/unittest/options/tst.ctypes.sh index 30a6c9b1..767de0db 100755 --- a/test/unittest/options/tst.ctypes.sh +++ b/test/unittest/options/tst.ctypes.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 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. # @@ -14,14 +14,14 @@ if [ ! -r $tmpdir/ctypes.ctf ]; then exit 1 fi -if objdump --help | grep ctf >/dev/null; then - objcopy --add-section=.ctf=$tmpdir/ctypes.ctf /bin/true $tmpdir/ctypes.o +if ${OBJDUMP} --help | grep ctf >/dev/null; then + ${OBJCOPY} --add-section=.ctf=$tmpdir/ctypes.ctf /bin/true $tmpdir/ctypes.o if [ $? -ne 0 ]; then echo "ERROR: Failed to create ELF object from ctypes.ctf" exit 1 fi - objdump --ctf=.ctf $tmpdir/ctypes.o | \ + ${OBJDUMP} --ctf=.ctf $tmpdir/ctypes.o | \ gawk '/CTF_VERSION/ { found = 1; next; } found && $1 ~ /0x[0-9A-Fa-f]+:/ { cnt++; next; } END { print "C CTF data" (found ? " " : " NOT ") "found"; diff --git a/test/unittest/options/tst.dtypes.sh b/test/unittest/options/tst.dtypes.sh index 441de098..ac6a8036 100755 --- a/test/unittest/options/tst.dtypes.sh +++ b/test/unittest/options/tst.dtypes.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 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. # @@ -14,14 +14,14 @@ if [ ! -r $tmpdir/dtypes.ctf ]; then exit 1 fi -if objdump --help | grep ctf >/dev/null; then - objcopy --add-section=.ctf=$tmpdir/dtypes.ctf /bin/true $tmpdir/dtypes.o +if ${OBJDUMP} --help | grep ctf >/dev/null; then + ${OBJCOPY} --add-section=.ctf=$tmpdir/dtypes.ctf /bin/true $tmpdir/dtypes.o if [ $? -ne 0 ]; then echo "ERROR: Failed to create ELF object from dtypes.ctf" exit 1 fi - objdump --ctf=.ctf $tmpdir/dtypes.o | \ + ${OBJDUMP} --ctf=.ctf $tmpdir/dtypes.o | \ gawk '/CTF_VERSION/ { found = 1; next; } found && $1 ~ /0x[0-9A-Fa-f]+:/ { cnt++; next; } END { print "D CTF data" (found ? " " : " NOT ") "found"; diff --git a/test/unittest/options/tst.linktype.sh b/test/unittest/options/tst.linktype.sh index 564d9b0f..7298d67a 100755 --- a/test/unittest/options/tst.linktype.sh +++ b/test/unittest/options/tst.linktype.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 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. # @@ -9,7 +9,6 @@ # @@nosort dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/linktype.$$.$RANDOM" @@ -61,7 +60,7 @@ function mytest() { fi # report whether the file format is recognized - objdump --file-headers prov.o |& gawk ' + ${OBJDUMP} --file-headers prov.o |& gawk ' /format not recognized/ { print "objdump does NOT recognize file format"; exit(0); diff --git a/test/unittest/options/tst.strip.sh b/test/unittest/options/tst.strip.sh index 054955fb..f7960d7a 100755 --- a/test/unittest/options/tst.strip.sh +++ b/test/unittest/options/tst.strip.sh @@ -1,13 +1,12 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 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 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/strip.$$.$RANDOM" @@ -48,7 +47,7 @@ fi # link with and without -xstrip, dumping the DOF section -objdump="objdump --full-contents --section=.SUNW_dof prov.o" +objdump="${OBJDUMP} --full-contents --section=.SUNW_dof prov.o" $dtrace $dt_flags -G -xstrip -s prov.d test.o if [ $? -ne 0 ]; then diff --git a/test/unittest/pid/tst.dash.sh b/test/unittest/pid/tst.dash.sh index f364e3e3..0289b609 100755 --- a/test/unittest/pid/tst.dash.sh +++ b/test/unittest/pid/tst.dash.sh @@ -54,7 +54,7 @@ int main(int c, char **v) { } EOF -gcc main.c +$CC main.c if [ $? -ne 0 ]; then echo ERROR compile exit 1 @@ -66,7 +66,7 @@ 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 ' + read ABS REL <<< `$OBJDUMP -d a.out | awk ' # Look for the function. /^[0-9a-f]* <'$func'>:$/ { diff --git a/test/unittest/pid/tst.offsets.sh b/test/unittest/pid/tst.offsets.sh index cc1a440d..23aad620 100755 --- a/test/unittest/pid/tst.offsets.sh +++ b/test/unittest/pid/tst.offsets.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. # @@ -54,7 +54,7 @@ main(int c, char **v) } EOF -gcc main.c +$CC main.c if [ $? -ne 0 ]; then echo ERROR in compiling exit 1 @@ -85,7 +85,7 @@ fi # hot and cold instructions in the function. # -objdump -d a.out | gawk ' +${OBJDUMP} -d a.out | gawk ' BEGIN { pc0 = 0; # First PC of loopfunc() pcjump = 0; # PC of the jump diff --git a/test/unittest/pid/tst.provregex1.sh b/test/unittest/pid/tst.provregex1.sh index c672b23f..5bc0bd51 100755 --- a/test/unittest/pid/tst.provregex1.sh +++ b/test/unittest/pid/tst.provregex1.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2008, 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. # @@ -23,10 +23,10 @@ cat > $DIR/Makefile < $DIR/main.c < $DIR/Makefile < $DIR/altlib.c < $DIR/Makefile < $DIR/Makefile </dev/null +echo 'int main (void) { }' | $CC -x c -c -o /dev/null -m32 - 2>/dev/null diff --git a/test/unittest/usdt/tst.dlclose1.sh b/test/unittest/usdt/tst.dlclose1.sh index a6bad02b..6e2c0da7 100755 --- a/test/unittest/usdt/tst.dlclose1.sh +++ b/test/unittest/usdt/tst.dlclose1.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 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. # @@ -29,7 +29,6 @@ # The second should not. dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/usdt-dlclose1.$$.$RANDOM" diff --git a/test/unittest/usdt/tst.dlclose2.sh b/test/unittest/usdt/tst.dlclose2.sh index 907685a6..88779fc5 100755 --- a/test/unittest/usdt/tst.dlclose2.sh +++ b/test/unittest/usdt/tst.dlclose2.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -15,7 +15,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/usdt-dlclose2.$$.$RANDOM" diff --git a/test/unittest/usdt/tst.dlclose3.sh b/test/unittest/usdt/tst.dlclose3.sh index 0b70906f..bcc1e0ed 100755 --- a/test/unittest/usdt/tst.dlclose3.sh +++ b/test/unittest/usdt/tst.dlclose3.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 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. # @@ -21,7 +21,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/usdt-dlclose3.$$.$RANDOM" diff --git a/test/unittest/usdt/tst.dlclose4.sh b/test/unittest/usdt/tst.dlclose4.sh index a84e3460..9e1a11c4 100755 --- a/test/unittest/usdt/tst.dlclose4.sh +++ b/test/unittest/usdt/tst.dlclose4.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. # @@ -15,7 +15,6 @@ PATH=/usr/bin:/usr/sbin:$PATH # dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/usdt-dlclose4.$$.$RANDOM" diff --git a/test/unittest/usdt/tst.eliminate.sh b/test/unittest/usdt/tst.eliminate.sh index e74896bb..e9fbf5e9 100755 --- a/test/unittest/usdt/tst.eliminate.sh +++ b/test/unittest/usdt/tst.eliminate.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 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. # @@xfail: Linux ld does not seem to support STV_ELIMINATE @@ -16,7 +16,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" @@ -71,13 +70,13 @@ if [ $? -ne 0 ]; then exit 1 fi -nm test.o | grep \$dtrace > /dev/null +${NM} test.o | grep \$dtrace > /dev/null if [ $? -ne 0 ]; then echo "no temporary symbols in the object file" >& 2 exit 1 fi -nm test | grep \$dtrace > /dev/null +${NM} test | grep \$dtrace > /dev/null if [ $? -eq 0 ]; then echo "failed to eliminate temporary symbols" >& 2 exit 1 diff --git a/test/unittest/usdt/tst.enable_pid.sh b/test/unittest/usdt/tst.enable_pid.sh index 207184d4..7f4f6869 100755 --- a/test/unittest/usdt/tst.enable_pid.sh +++ b/test/unittest/usdt/tst.enable_pid.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. # @@ -14,7 +14,6 @@ PATH=/usr/bin:/usr/sbin:$PATH # dtrace=$1 -CC=/usr/bin/gcc CFLAGS= DIRNAME="$tmpdir/usdt-enable_pid.$$.$RANDOM" @@ -120,7 +119,7 @@ if [ $? -ne 0 ]; then echo "failed to generate header file" >&2 exit 1 fi -cc $test_cppflags -c main.c +$CC $test_cppflags -c main.c if [ $? -ne 0 ]; then echo "failed to compile test" >&2 exit 1 @@ -130,7 +129,7 @@ if [ $? -ne 0 ]; then echo "failed to create DOF" >&2 exit 1 fi -cc $test_cppflags -o main main.o prov.o +$CC $test_cppflags -o main main.o prov.o if [ $? -ne 0 ]; then echo "failed to link final executable" >&2 exit 1 diff --git a/test/unittest/usdt/tst.enabled.sh b/test/unittest/usdt/tst.enabled.sh index 4cd1eccd..a180f962 100755 --- a/test/unittest/usdt/tst.enabled.sh +++ b/test/unittest/usdt/tst.enabled.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.enabled2.sh b/test/unittest/usdt/tst.enabled2.sh index 1732085e..b174ef4c 100755 --- a/test/unittest/usdt/tst.enabled2.sh +++ b/test/unittest/usdt/tst.enabled2.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2008, 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. # @@ -15,7 +15,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.entryreturn.sh b/test/unittest/usdt/tst.entryreturn.sh index 84af9672..03418e7b 100755 --- a/test/unittest/usdt/tst.entryreturn.sh +++ b/test/unittest/usdt/tst.entryreturn.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 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. # @@ -13,7 +13,6 @@ fi # @@xfail: dtv2, no wildcard usdt probes yet dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.exec-dof-replacement.sh b/test/unittest/usdt/tst.exec-dof-replacement.sh index 6d547cce..b7ec5f2d 100755 --- a/test/unittest/usdt/tst.exec-dof-replacement.sh +++ b/test/unittest/usdt/tst.exec-dof-replacement.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -14,7 +14,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.execstack.sh b/test/unittest/usdt/tst.execstack.sh index e7b59105..42da7035 100755 --- a/test/unittest/usdt/tst.execstack.sh +++ b/test/unittest/usdt/tst.execstack.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -11,11 +11,8 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" -OBJDUMP=/usr/bin/objdump -READELF=/usr/bin/readelf DIRNAME="$tmpdir/usdt-execstack.$$.$RANDOM" mkdir -p $DIRNAME diff --git a/test/unittest/usdt/tst.fork.sh b/test/unittest/usdt/tst.fork.sh index 9b2b372a..e82463f9 100755 --- a/test/unittest/usdt/tst.fork.sh +++ b/test/unittest/usdt/tst.fork.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -12,7 +12,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.guess32.sh b/test/unittest/usdt/tst.guess32.sh index 7a130e17..21961236 100755 --- a/test/unittest/usdt/tst.guess32.sh +++ b/test/unittest/usdt/tst.guess32.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.guess64.sh b/test/unittest/usdt/tst.guess64.sh index 23b7a241..417dcec9 100755 --- a/test/unittest/usdt/tst.guess64.sh +++ b/test/unittest/usdt/tst.guess64.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.header.sh b/test/unittest/usdt/tst.header.sh index c5e411be..521e9fd1 100755 --- a/test/unittest/usdt/tst.header.sh +++ b/test/unittest/usdt/tst.header.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.lingering.sh b/test/unittest/usdt/tst.lingering.sh index 079acb75..148345cf 100755 --- a/test/unittest/usdt/tst.lingering.sh +++ b/test/unittest/usdt/tst.lingering.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -14,7 +14,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.link-idempotence.sh b/test/unittest/usdt/tst.link-idempotence.sh index 643ba10c..caa49533 100755 --- a/test/unittest/usdt/tst.link-idempotence.sh +++ b/test/unittest/usdt/tst.link-idempotence.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.linkpriv.sh b/test/unittest/usdt/tst.linkpriv.sh index 2c89f5d4..5f637e85 100755 --- a/test/unittest/usdt/tst.linkpriv.sh +++ b/test/unittest/usdt/tst.linkpriv.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="-std=gnu99 $test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.linkunpriv.sh b/test/unittest/usdt/tst.linkunpriv.sh index 9ef38639..b00d532e 100755 --- a/test/unittest/usdt/tst.linkunpriv.sh +++ b/test/unittest/usdt/tst.linkunpriv.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -13,7 +13,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" DIRNAME="$tmpdir/usdt-linkunpriv.$$.$RANDOM" diff --git a/test/unittest/usdt/tst.manyprobes.sh b/test/unittest/usdt/tst.manyprobes.sh index c0deb8df..6e894f2c 100755 --- a/test/unittest/usdt/tst.manyprobes.sh +++ b/test/unittest/usdt/tst.manyprobes.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 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. # @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" DIRNAME="$tmpdir/usdt-manyprobes.$$.$RANDOM" diff --git a/test/unittest/usdt/tst.manyprocs.sh b/test/unittest/usdt/tst.manyprocs.sh index 58550302..e157d05a 100755 --- a/test/unittest/usdt/tst.manyprocs.sh +++ b/test/unittest/usdt/tst.manyprocs.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -14,7 +14,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.multiple.sh b/test/unittest/usdt/tst.multiple.sh index 440a7d7b..8734a110 100755 --- a/test/unittest/usdt/tst.multiple.sh +++ b/test/unittest/usdt/tst.multiple.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.multiprov-dupprobe-shlibs.sh b/test/unittest/usdt/tst.multiprov-dupprobe-shlibs.sh index 6595737f..2fc17e58 100755 --- a/test/unittest/usdt/tst.multiprov-dupprobe-shlibs.sh +++ b/test/unittest/usdt/tst.multiprov-dupprobe-shlibs.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. # @@ -13,7 +13,6 @@ # @@nosort dtrace=$1 -CC=/usr/bin/gcc DIRNAME="$tmpdir/usdt-multiprov-dupprobe-shlibs.$$.$RANDOM" mkdir -p $DIRNAME diff --git a/test/unittest/usdt/tst.multitrace.sh b/test/unittest/usdt/tst.multitrace.sh index 262c7828..81f43f76 100755 --- a/test/unittest/usdt/tst.multitrace.sh +++ b/test/unittest/usdt/tst.multitrace.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -14,7 +14,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.nusdtprobes.sh b/test/unittest/usdt/tst.nusdtprobes.sh index f275f921..93c56e38 100755 --- a/test/unittest/usdt/tst.nusdtprobes.sh +++ b/test/unittest/usdt/tst.nusdtprobes.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. # @@ -66,7 +66,7 @@ if [ $? -ne 0 ]; then echo "failed to generate header file" >&2 exit 1 fi -gcc $test_cppflags -c main.c +$CC $test_cppflags -c main.c if [ $? -ne 0 ]; then echo "failed to compile test" >&2 exit 1 @@ -76,7 +76,7 @@ if [ $? -ne 0 ]; then echo "failed to create DOF" >&2 exit 1 fi -gcc $test_ldflags -o main main.o prov.o +$CC $test_ldflags -o main main.o prov.o if [ $? -ne 0 ]; then echo "failed to link final executable" >&2 exit 1 diff --git a/test/unittest/usdt/tst.onlyenabled.sh b/test/unittest/usdt/tst.onlyenabled.sh index d3487834..9db5dc46 100755 --- a/test/unittest/usdt/tst.onlyenabled.sh +++ b/test/unittest/usdt/tst.onlyenabled.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.pidprobes.sh b/test/unittest/usdt/tst.pidprobes.sh index 0c75d796..72434eb9 100755 --- a/test/unittest/usdt/tst.pidprobes.sh +++ b/test/unittest/usdt/tst.pidprobes.sh @@ -69,20 +69,20 @@ if [ $? -ne 0 ]; then echo "failed to generate header file" >&2 exit 1 fi -cc $test_cppflags -c main.c +$CC $test_cppflags -c main.c if [ $? -ne 0 ]; then echo "failed to compile test" >&2 exit 1 fi if [[ `uname -m` = "aarch64" ]]; then - objdump -d main.o > disasm_foo.txt.before + $OBJDUMP -d main.o > disasm_foo.txt.before fi $dtrace $dt_flags -G -64 -s prov.d main.o if [ $? -ne 0 ]; then echo "failed to create DOF" >&2 exit 1 fi -cc $test_ldflags -o main main.o prov.o +$CC $test_ldflags -o main main.o prov.o if [ $? -ne 0 ]; then echo "failed to link final executable" >&2 exit 1 @@ -104,7 +104,7 @@ fi # Disassemble foo(). (simplify with --disassemble=foo) -objdump -d main | awk ' +$OBJDUMP -d main | awk ' BEGIN { use = 0 } # start by not printing lines use == 1 && NF == 0 { exit } # if printing lines but hit a blank, then exit use == 1 { print } # print lines @@ -112,7 +112,7 @@ use == 1 { print } # print lines ' > disasm_foo.txt if [ $? -ne 0 ]; then echo cannot objdump main - objdump -d main + $OBJDUMP -d main exit 1 fi @@ -277,7 +277,7 @@ done pc_return=`awk '/'$pid' pid'$pid':main:foo:return/ { print $NF }' dtrace.out` -objdump -d main | awk ' +$OBJDUMP -d main | awk ' /^[0-9a-f]* <.*>:$/ { myfunc = $NF } # enter a new function /^ *'$pc_return'/ { print myfunc; exit(0) } # report the function $pc_return is in ' > return_func.out diff --git a/test/unittest/usdt/tst.pie.sh b/test/unittest/usdt/tst.pie.sh index 0d62c376..a2c12a26 100755 --- a/test/unittest/usdt/tst.pie.sh +++ b/test/unittest/usdt/tst.pie.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 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. # @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="-fno-inline -pie $test_cppflags" LDFLAGS="-pie $test_ldflags" diff --git a/test/unittest/usdt/tst.reeval.sh b/test/unittest/usdt/tst.reeval.sh index 371eee3d..069248f5 100755 --- a/test/unittest/usdt/tst.reeval.sh +++ b/test/unittest/usdt/tst.reeval.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 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. # @@ -12,7 +12,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.static.sh b/test/unittest/usdt/tst.static.sh index 81b3ba04..dd96b0ff 100755 --- a/test/unittest/usdt/tst.static.sh +++ b/test/unittest/usdt/tst.static.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -11,7 +11,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.static2.sh b/test/unittest/usdt/tst.static2.sh index 115a9551..2606ecf3 100755 --- a/test/unittest/usdt/tst.static2.sh +++ b/test/unittest/usdt/tst.static2.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -15,7 +15,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/unittest/usdt/tst.user.sh b/test/unittest/usdt/tst.user.sh index 30513acc..62489705 100755 --- a/test/unittest/usdt/tst.user.sh +++ b/test/unittest/usdt/tst.user.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2006, 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. # @@ -13,7 +13,6 @@ if [ $# != 1 ]; then fi dtrace=$1 -CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" diff --git a/test/utils/workload_analyze_loop.sh b/test/utils/workload_analyze_loop.sh index 3bbadf78..7edce7b0 100755 --- a/test/utils/workload_analyze_loop.sh +++ b/test/utils/workload_analyze_loop.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 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. @@ -13,7 +13,7 @@ if [ ! -e $prog ]; then exit 1 fi -objdump -d $prog | gawk -v myarch=$(uname -m) ' +${OBJDUMP} -d $prog | gawk -v myarch=$(uname -m) ' # decide whether to track instructions (which we number n = 1, 2, 3, ...) or not (n < 0) # specifically, do not track instructions until we find the disassembly for
BEGIN { n = -1; } -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:14:58 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:14:58 -0400 Subject: [DTrace-devel] [PATCH 05/17] dof_parser: remove pointless comment Message-ID: Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh --- libcommon/dof_parser.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/libcommon/dof_parser.c b/libcommon/dof_parser.c index 5b3dde36..58bbd604 100644 --- a/libcommon/dof_parser.c +++ b/libcommon/dof_parser.c @@ -89,9 +89,6 @@ dof_copyin_helper(int in, int out, int *ok) dof_helper_t *dh; size_t i; - /* - * First get the header, which gives the size of everything else. - */ dh = malloc(sizeof(dof_helper_t)); if (!dh) abort(); -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:14:59 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:14:59 -0400 Subject: [DTrace-devel] [PATCH 06/17] dof_parser: restructure the dof_copyin*() code Message-ID: All logic for reading data from the DOF parser pipe is now consolidated in dof_copyin(). Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh --- dtprobed/dtprobed.c | 6 +-- libcommon/dof_parser.c | 115 ++++++++++++++++------------------------- libcommon/dof_parser.h | 4 +- 3 files changed, 49 insertions(+), 76 deletions(-) diff --git a/dtprobed/dtprobed.c b/dtprobed/dtprobed.c index 5f260f0a..a9944894 100644 --- a/dtprobed/dtprobed.c +++ b/dtprobed/dtprobed.c @@ -302,7 +302,7 @@ cleanup_userdata(void) } /* - * Parse a piece of DOF. Return 0 iff the pipe has closed and no more parsing + * Parse a piece of DOF. Return 0 iff the pipe has closed or no more parsing * is possible. */ static int @@ -312,9 +312,9 @@ parse_dof(int in, int out) dof_helper_t *dh; dof_hdr_t *dof; - dh = dof_copyin_helper(in, out, &ok); + dh = dof_copyin_helper(in); if (!dh) - return ok; + return 0; dof = dof_copyin_dof(in, out, &ok); if (!dof) { diff --git a/libcommon/dof_parser.c b/libcommon/dof_parser.c index 58bbd604..ec80cee8 100644 --- a/libcommon/dof_parser.c +++ b/libcommon/dof_parser.c @@ -83,22 +83,24 @@ static void dof_error(int out, int err_no, const char *fmt, ...) free(msg); } -dof_helper_t * -dof_copyin_helper(int in, int out, int *ok) +static char * +dof_copyin(int in, char *buf_, size_t sz) { - dof_helper_t *dh; + char *buf = buf_; size_t i; - dh = malloc(sizeof(dof_helper_t)); - if (!dh) - abort(); + if (!buf) { + buf = malloc(sz); + if (!buf) + abort(); + } - memset(dh, 0, sizeof(dof_helper_t)); + memset(buf, 0, sz); - for (i = 0; i < sizeof(dof_helper_t);) { + for (i = 0; i < sz; ) { size_t ret; - ret = read(in, ((char *) dh) + i, sizeof(dof_helper_t) - i); + ret = read(in, buf + i, sz - i); if (ret < 0) { switch (errno) { @@ -119,89 +121,60 @@ dof_copyin_helper(int in, int out, int *ok) i += ret; } - *ok = 1; - return dh; + return buf; err: - *ok = 0; - free(dh); + if (!buf_) + free(buf); return NULL; } +dof_helper_t * +dof_copyin_helper(int in) +{ + return (dof_helper_t *)dof_copyin(in, NULL, sizeof(dof_helper_t)); +} + dof_hdr_t * dof_copyin_dof(int in, int out, int *ok) { dof_hdr_t *dof; - size_t i, sz; *ok = 1; - /* - * First get the header, which gives the size of everything else. - */ - dof = malloc(sizeof(dof_hdr_t)); + /* First get the header, which gives the size of everything else. */ + dof = (dof_hdr_t *)dof_copyin(in, NULL, sizeof(dof_hdr_t)); if (!dof) abort(); - memset(dof, 0, sizeof(dof_hdr_t)); - - for (i = 0, sz = sizeof(dof_hdr_t); i < sz;) { - size_t ret; - - ret = read(in, ((char *) dof) + i, sz - i); - - if (ret < 0) { - switch (errno) { - case EINTR: - continue; - default: - goto err; - } - } - - /* - * EOF: parsing done, process shutting down or message - * truncated. Fail, in any case. - */ - if (ret == 0) - goto err; - - /* Allocate more room if needed for the reply. */ - if (i < sizeof(dof_hdr_t) && - i + ret >= sizeof(dof_hdr_t)) { - dof_hdr_t *new_dof; - - if (dof->dofh_loadsz >= dof_maxsize) { - dof_error(out, E2BIG, "load size %zi exceeds maximum %zi", - dof->dofh_loadsz, dof_maxsize); - return NULL; - } - - if (dof->dofh_loadsz < sizeof(dof_hdr_t)) { - dof_error(out, EINVAL, "invalid load size %zi, " - "smaller than header size %zi", dof->dofh_loadsz, - sizeof(dof_hdr_t)); - return NULL; - } + /* Validate the DOF load size. */ + if (dof->dofh_loadsz >= dof_maxsize) { + dof_error(out, E2BIG, "load size %zi exceeds maximum %zi", + dof->dofh_loadsz, dof_maxsize); + return NULL; + } - new_dof = realloc(dof, dof->dofh_loadsz); - if (!new_dof) - abort(); + if (dof->dofh_loadsz < sizeof(dof_hdr_t)) { + dof_error(out, EINVAL, "invalid load size %zi, " + "smaller than header size %zi", dof->dofh_loadsz, + sizeof(dof_hdr_t)); + return NULL; + } - memset(((char *)new_dof) + i + ret, 0, new_dof->dofh_loadsz - (i + ret)); - dof = new_dof; - sz = dof->dofh_loadsz; - } + /* Resize the allocated memory to fit the actual data as well. */ + dof = realloc(dof, dof->dofh_loadsz); + if (!dof) + abort(); - i += ret; + /* Read the actual data in the allocated buffer. */ + if (!dof_copyin(in, ((char *)dof) + sizeof(dof_hdr_t), + dof->dofh_loadsz - sizeof(dof_hdr_t))) { + *ok = 0; + free(dof); + return NULL; } return dof; - -err: - *ok = 0; - free(dof); - return NULL; } static void dof_destroy(dof_helper_t *dhp, dof_hdr_t *dof) diff --git a/libcommon/dof_parser.h b/libcommon/dof_parser.h index 75aa3082..de6cea4c 100644 --- a/libcommon/dof_parser.h +++ b/libcommon/dof_parser.h @@ -180,9 +180,9 @@ dof_parsed_t *dof_parser_host_read(int in, int timeout); /* * Get a dof_helper_t from the input fd. * - * Set OK to zero if no further parsing is possible. + * Returns NULL on failure - no further processing is possible in that case. */ -dof_helper_t *dof_copyin_helper(int in, int out, int *ok); +dof_helper_t *dof_copyin_helper(int in); /* * Get a buffer of DOF from the input fd and sanity-check it. -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:01 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:01 -0400 Subject: [DTrace-devel] [PATCH 08/17] dtprobed: fix probe name debug output Message-ID: Debug output while reading dof_parsed_t structures was printing the probe names as provider->provider.name and probe->probe.name, but probe.name is a 0-separated concatenation of the probe name elements. It only printed the module name. Corrected to print the full probe name. Also moved it to the proper place (when a new probe is read rather than for every tracepoint). Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Reviewed-by: Eugene Loh --- dtprobed/dtprobed.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/dtprobed/dtprobed.c b/dtprobed/dtprobed.c index dfdce02c..de15e546 100644 --- a/dtprobed/dtprobed.c +++ b/dtprobed/dtprobed.c @@ -802,6 +802,18 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, if (!probe || probe->type != DIT_PROBE) goto err; + if (_dtrace_debug) { + const char *mod, *fun, *prb; + + mod = probe->probe.name; + fun = mod + strlen(mod) + 1; + prb = fun + strlen(fun) + 1; + fuse_log(FUSE_LOG_DEBUG, + "Parser read: adding %s:%s:%s:%s to stash\n", + provider->provider.name, + mod, fun, prb); + } + if (dof_stash_push_parsed(&accum, probe) < 0) goto oom; @@ -814,9 +826,6 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, tp->type == DIT_PROBE || tp->type == DIT_EOF) goto err; - fuse_log(FUSE_LOG_DEBUG, "Parser read: adding %s:%s to stash\n", - provider->provider.name, probe->probe.name); - if (dof_stash_push_parsed(&accum, tp) < 0) goto oom; -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:00 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:00 -0400 Subject: [DTrace-devel] [PATCH 07/17] dof_parser: generic parser framework to support multiple parsers Message-ID: To prepare for non-DOF section based USDT probe definitions, the data passed from dtprobed to the USDT data parser is more generic. The dof_helper_t structure is passed first, followed by a block count, and that number of data blocks, passed as a size followed by the content. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh --- dtprobed/dof_stash.c | 11 +- dtprobed/dof_stash.h | 7 +- dtprobed/dtprobed.c | 62 +-- libcommon/Build | 2 +- libcommon/usdt_parser.c | 227 +++++++++ libcommon/{dof_parser.h => usdt_parser.h} | 70 ++- libcommon/{dof_parser.c => usdt_parser_dof.c} | 462 ++++++------------ .../{dof_parser_host.c => usdt_parser_host.c} | 46 +- libdtrace/dt_pid.c | 2 +- 9 files changed, 513 insertions(+), 376 deletions(-) create mode 100644 libcommon/usdt_parser.c rename libcommon/{dof_parser.h => usdt_parser.h} (66%) rename libcommon/{dof_parser.c => usdt_parser_dof.c} (68%) rename libcommon/{dof_parser_host.c => usdt_parser_host.c} (71%) diff --git a/dtprobed/dof_stash.c b/dtprobed/dof_stash.c index 296987ad..6a4ecb86 100644 --- a/dtprobed/dof_stash.c +++ b/dtprobed/dof_stash.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace; DOF state storage management. - * 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. * @@ -1568,7 +1568,7 @@ int reparse_dof(int out, int in, int (*reparse)(int pid, int out, int in, dev_t dev, ino_t ino, dev_t unused1, ino_t unused2, dof_helper_t *dh, - const void *in_buf, size_t in_bufsz, int reparsing), + const usdt_data_t *data, int reparsing), int force) { DIR *all_pids_dir; @@ -1642,6 +1642,7 @@ reparse_dof(int out, int in, size_t dof_size, dh_size; void *dof = NULL; void *dh = NULL; + usdt_data_t data; if (errno != 0) { fuse_log(FUSE_LOG_ERR, "reparsing DOF: cannot read per-PID DOF mappings for pid %s: %s\n", @@ -1742,7 +1743,11 @@ reparse_dof(int out, int in, fuse_log(FUSE_LOG_DEBUG, "Reparsing DOF for PID %s, mapping %s\n", pid_ent->d_name, mapping_ent->d_name); - if (reparse(pid, out, in, dev, ino, 0, 0, dh, dof, dof_size, 1) < 0) + + data.buf = dof; + data.size = dof_size; + data.next = NULL; + if (reparse(pid, out, in, dev, ino, 0, 0, dh, &data, 1) < 0) fuse_log(FUSE_LOG_ERR, "when reparsing DOF, cannot parse DOF for PID %s, mapping %s: ignored\n", pid_ent->d_name, mapping_ent->d_name); free(dof); diff --git a/dtprobed/dof_stash.h b/dtprobed/dof_stash.h index d44a2bda..1017d2d2 100644 --- a/dtprobed/dof_stash.h +++ b/dtprobed/dof_stash.h @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace; DOF storage for later probe removal. - * 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. */ @@ -12,7 +12,7 @@ #include #include -#include "dof_parser.h" +#include "usdt_parser.h" typedef struct dof_parsed_list { dt_list_t list; @@ -35,8 +35,7 @@ void dof_stash_prune_dead(void); int reparse_dof(int out, int in, int (*reparse)(int pid, int out, int in, dev_t dev, ino_t ino, dev_t unused1, ino_t unused2, dof_helper_t *dh, - const void *in_buf, size_t in_bufsz, - int reparsing), + const usdt_data_t *data, int reparsing), int force); #endif diff --git a/dtprobed/dtprobed.c b/dtprobed/dtprobed.c index a9944894..dfdce02c 100644 --- a/dtprobed/dtprobed.c +++ b/dtprobed/dtprobed.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -62,7 +63,7 @@ #include #include -#include "dof_parser.h" +#include "usdt_parser.h" #include "dof_stash.h" #include "libproc.h" @@ -96,8 +97,8 @@ static const struct cuse_lowlevel_ops dtprobed_clop = { static int process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, - dev_t exec_inum, dof_helper_t *dh, const void *in_buf, - size_t in_bufsz, int reparsing); + dev_t exec_inum, dof_helper_t *dh, const usdt_data_t *data, + int reparsing); static void log_msg(enum fuse_log_level level, const char *fmt, va_list ap) @@ -310,29 +311,29 @@ parse_dof(int in, int out) { int ok; dof_helper_t *dh; - dof_hdr_t *dof; + usdt_data_t *data; - dh = dof_copyin_helper(in); + dh = usdt_copyin_helper(in); if (!dh) return 0; - dof = dof_copyin_dof(in, out, &ok); - if (!dof) { + data = usdt_copyin_data(in, out, &ok); + if (!data) { free(dh); return ok; } - dof_parse(out, dh, dof); + usdt_parse(out, dh, data); return ok; } /* - * Kick off the sandboxed DOF parser. This is run in a seccomp()ed subprocess, + * Kick off the sandboxed USDT parser. This is run in a seccomp()ed subprocess, * and sends a stream of dof_parsed_t back to this process. */ static void -dof_parser_start(void) +usdt_parser_start(void) { int parser_in[2], parser_out[2]; if ((pipe(parser_in) < 0) || @@ -395,10 +396,10 @@ dof_parser_start(void) } /* - * Clean up wreckage if the DOF parser dies: optionally restart it. + * Clean up wreckage if the USDT parser dies: optionally restart it. */ static void -dof_parser_tidy(int restart) +usdt_parser_tidy(int restart) { int status = 0; @@ -413,13 +414,13 @@ dof_parser_tidy(int restart) close(parser_out_pipe); if (restart) - dof_parser_start(); + usdt_parser_start(); } static dof_parsed_t * -dof_read(pid_t pid, int in) +usdt_read(pid_t pid, int in) { - dof_parsed_t *reply = dof_parser_host_read(in, timeout); + dof_parsed_t *reply = usdt_parser_host_read(in, timeout); if (!reply) return NULL; @@ -497,6 +498,7 @@ helper_ioctl(fuse_req_t req, int cmd, void *arg, dev_t dev = 0, exec_dev = 0; ino_t inum = 0, exec_inum = 0; int gen; + usdt_data_t data; /* * We can just ignore FUSE_IOCTL_COMPAT: the 32-bit and 64-bit versions @@ -687,9 +689,12 @@ chunks_done: &exec_dev, &exec_inum)) < 0) goto process_err; + data.buf = (void *)buf; + data.size = userdata->dof_hdr.dofh_loadsz; + data.next = NULL; if ((gen = process_dof(pid, parser_out_pipe, parser_in_pipe, dev, inum, exec_dev, exec_inum, &userdata->dh, - buf, userdata->dof_hdr.dofh_loadsz, 0)) < 0) + &data, 0)) < 0) goto process_err; if (fuse_reply_ioctl(req, gen, NULL, 0) < 0) @@ -741,8 +746,8 @@ process_err: */ static int process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, - dev_t exec_inum, dof_helper_t *dh, const void *in_buf, - size_t in_bufsz, int reparsing) + dev_t exec_inum, dof_helper_t *dh, const usdt_data_t *data, + int reparsing) { dof_parsed_t *provider; size_t i; @@ -753,8 +758,7 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, do { errmsg = "DOF parser write failed"; - while ((errno = dof_parser_host_write(out, dh, - (dof_hdr_t *) in_buf)) == EAGAIN); + while ((errno = usdt_parser_host_write(out, dh, data)) == EAGAIN); if (errno != 0) goto err; @@ -765,7 +769,7 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, */ errmsg = "parsed DOF read failed"; - provider = dof_read(pid, in); + provider = usdt_read(pid, in); if (!provider) { if (tries++ > 1) goto err; @@ -773,7 +777,7 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, * Tidying reopens the parser in and out pipes: catch * up with this. */ - dof_parser_tidy(1); + usdt_parser_tidy(1); out = parser_out_pipe; in = parser_in_pipe; continue; @@ -791,7 +795,7 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, provider->provider.name, provider->provider.nprobes); for (i = 0; i < provider->provider.nprobes; i++) { - dof_parsed_t *probe = dof_read(pid, in); + dof_parsed_t *probe = usdt_read(pid, in); size_t j; errmsg = "no probes in this provider, or parse state corrupt"; @@ -803,7 +807,7 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, j = 0; do { - dof_parsed_t *tp = dof_read(pid, in); + dof_parsed_t *tp = usdt_read(pid, in); errmsg = "no tracepoints in a probe, or parse state corrupt"; if (!tp || tp->type == DIT_PROVIDER || @@ -822,7 +826,7 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, } errmsg = "subsequent provider read failed, or stream not properly terminated"; - provider = dof_read(pid, in); + provider = usdt_read(pid, in); if (!provider) goto err; } @@ -834,7 +838,7 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, if (!reparsing) if ((gen = dof_stash_add(pid, dev, inum, exec_dev, exec_inum, dh, - in_buf, in_bufsz)) < 0) + data->buf, data->size)) < 0) goto fileio; if (dof_stash_write_parsed(pid, dev, inum, &accum) < 0) { @@ -860,7 +864,7 @@ fileio: proc_err: dof_stash_free(&accum); - dof_parser_tidy(1); + usdt_parser_tidy(1); return -1; } @@ -1071,7 +1075,7 @@ main(int argc, char *argv[]) testing = 1; } - dof_parser_start(); + usdt_parser_start(); if (dof_stash_init(statedir) < 0) exit(1); @@ -1102,7 +1106,7 @@ main(int argc, char *argv[]) ret = loop(); - dof_parser_tidy(0); + usdt_parser_tidy(0); teardown_device(); if (ret == 0) diff --git a/libcommon/Build b/libcommon/Build index e8908e7c..f64545ed 100644 --- a/libcommon/Build +++ b/libcommon/Build @@ -9,7 +9,7 @@ LIBS += libcommon 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_SOURCES = usdt_parser.c usdt_parser_dof.c usdt_parser_host.c dt_list.c libcommon_NOCFLAGS := -D_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -D_FORTIFY_SOURCE=2 -D_FORTIFY_SOURCE=3 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=1 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=2 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 libcommon_NOCPPFLAGS := -D_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -D_FORTIFY_SOURCE=2 -D_FORTIFY_SOURCE=3 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=1 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=2 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 libcommon_LIBSOURCES = libcommon diff --git a/libcommon/usdt_parser.c b/libcommon/usdt_parser.c new file mode 100644 index 00000000..f301fd56 --- /dev/null +++ b/libcommon/usdt_parser.c @@ -0,0 +1,227 @@ +/* + * Oracle Linux DTrace; USDT definitions parser. + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "usdt_parser.h" + +size_t usdt_maxcount = 2; +size_t usdt_maxsize = 256 * 1024 * 1024; + +_dt_printflike_(3, 4) +void +usdt_error(int out, int err_no, const char *fmt, ...) +{ + dof_parsed_t *parsed; + size_t sz; + char *msg; + va_list ap; + + /* + * Not much we can do on OOM of errors other than abort, forcing a + * parser restart, which hopefully will have enough memory to report the + * error properly. + */ + va_start(ap, fmt); + if (vasprintf(&msg, fmt, ap) < 0) + abort(); + va_end(ap); + + sz = offsetof(dof_parsed_t, err.err) + strlen(msg) + 1; + parsed = malloc(sz); + + if (!parsed) + abort(); + + memset(parsed, 0, sz); + parsed->size = sz; + parsed->type = DIT_ERR; + parsed->err.err_no = err_no; + strcpy(parsed->err.err, msg); + + usdt_parser_write_one(out, parsed, parsed->size); + free(parsed); + free(msg); +} + +static char * +usdt_copyin(int in, char *buf_, size_t sz) +{ + char *buf = buf_; + size_t i; + + if (!buf) { + buf = malloc(sz); + if (!buf) + abort(); + } + + memset(buf, 0, sz); + + for (i = 0; i < sz; ) { + size_t ret; + + ret = read(in, buf + i, sz - i); + + if (ret < 0) { + switch (errno) { + case EINTR: + continue; + default: + goto err; + } + } + + /* + * EOF: parsing done, process shutting down or message + * truncated. Fail, in any case. + */ + if (ret == 0) + goto err; + + i += ret; + } + + return buf; + +err: + if (!buf_) + free(buf); + return NULL; +} + +dof_helper_t * +usdt_copyin_helper(int in) +{ + return (dof_helper_t *)usdt_copyin(in, NULL, sizeof(dof_helper_t)); +} + +static usdt_data_t * +usdt_copyin_block(int in, int out, int *ok) +{ + usdt_data_t *data; + + *ok = 1; + + data = malloc(sizeof(usdt_data_t)); + if (!data) + abort(); + + memset(data, 0, sizeof(usdt_data_t)); + + /* Get the size of the data block. */ + if (!usdt_copyin(in, (char *)&data->size, sizeof(data->size))) + abort(); + + /* Validate the data size. */ + if (data->size >= usdt_maxsize) { + usdt_error(out, E2BIG, "data size %zi exceeds maximum %zi", + data->size, usdt_maxsize); + return NULL; + } + + /* Get the data. */ + data->buf = (void *)usdt_copyin(in, NULL, data->size); + if (!data->buf) { + *ok = 0; + free(data); + return NULL; + } + + return data; +} + +static void +usdt_destroy_data(usdt_data_t *data) +{ + while (data) { + usdt_data_t *next = data->next; + + free(data->buf); + free(data); + data = next; + } +} + +usdt_data_t * +usdt_copyin_data(int in, int out, int *ok) +{ + usdt_data_t *first = NULL, *last; + size_t cnt; + + *ok = 1; + + /* Get the number of data blocks to follow. */ + if (!usdt_copyin(in, (char *)&cnt, sizeof(cnt))) + abort(); + + if (cnt >= usdt_maxcount) { + usdt_error(out, E2BIG, "block count %zi exceeds maximum %zi", + cnt, usdt_maxcount); + return NULL; + } + + /* Get the data blocks (for each, size followed by content). */ + while (cnt-- > 0) { + usdt_data_t *blk; + + if ((blk = usdt_copyin_block(in, out, ok)) == NULL) + goto err; + + if (first == NULL) + first = last = blk; + else { + last->next = blk; + last = blk; + } + } + + return first; + +err: + usdt_destroy_data(first); + + return NULL; +} + +static void +usdt_destroy(dof_helper_t *dhp, usdt_data_t *data) +{ + free(dhp); + usdt_destroy_data(data); +} + +void +usdt_parse(int out, dof_helper_t *dhp, usdt_data_t *data) +{ + dof_parsed_t eof; + + if (usdt_parse_dof(out, dhp, data->buf) != 0) + goto err; + + /* + * Always emit an EOF, to wake up the caller if nothing else, but also + * to notify the caller that there are no more providers to read. + */ + memset(&eof, 0, sizeof(dof_parsed_t)); + + eof.size = offsetof(dof_parsed_t, provider.nprobes); + eof.type = DIT_EOF; + usdt_parser_write_one(out, &eof, eof.size); + +err: + usdt_destroy(dhp, data); +} diff --git a/libcommon/dof_parser.h b/libcommon/usdt_parser.h similarity index 66% rename from libcommon/dof_parser.h rename to libcommon/usdt_parser.h index de6cea4c..9dd97e28 100644 --- a/libcommon/dof_parser.h +++ b/libcommon/usdt_parser.h @@ -1,22 +1,33 @@ /* - * Oracle Linux DTrace; DOF parser interface with the outside world - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Oracle Linux DTrace; USDT definitions parser interface. + * Copyright (c) 2022, 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. */ -#ifndef _DOF_PARSER_H -#define _DOF_PARSER_H +#ifndef _USDT_PARSER_H +#define _USDT_PARSER_H #include #include +#include #include #include /* - * Result of DOF probe parsing. The order of elements in the parsed stream - * is: + * Data transfer unit for the DOF parser. + */ +typedef struct usdt_data usdt_data_t; +struct usdt_data { + size_t size; + void *buf; + usdt_data_t *next; +}; + +/* + * Result of USDT definitions parsing. The order of elements in the parsed + * stream is: * * DIT_PROVIDER (at least 1, which contains...) * DIT_PROBE (at least 1, each of which has...) @@ -156,55 +167,70 @@ typedef struct dof_parsed { } dof_parsed_t; /* - * Host-side: in dof_parser_host.c. The host is the - * non-jailed process that talks to the jailed parser. + * Host-side: in usdt_parser_host.c. + * The host is the non-jailed process that talks to the jailed parser. */ /* - * Write the DOF to the parser pipe OUT. + * Write the USDT definitions data to the parser pipe OUT. * * Returns 0 on success or a positive errno value on error. */ -int dof_parser_host_write(int out, const dof_helper_t *dh, dof_hdr_t *dof); +int usdt_parser_host_write(int out, const dof_helper_t *dh, + const usdt_data_t *data); /* - * Read a single DOF structure from a parser pipe. Wait at most TIMEOUT seconds - * to do so. + * Read a single dof_parsed_t structure from a parser pipe. Wait at most + * TIMEOUT seconds to do so. * * Returns NULL and sets errno on error. */ -dof_parsed_t *dof_parser_host_read(int in, int timeout); +dof_parsed_t *usdt_parser_host_read(int in, int timeout); -/* Parser-side: in dof_parser.c. */ +/* Parser-side: in usdt_parser.c. */ + +/* + * Report a parser error. + */ +void usdt_error(int out, int err_no, const char *fmt, ...); /* * Get a dof_helper_t from the input fd. * * Returns NULL on failure - no further processing is possible in that case. */ -dof_helper_t *dof_copyin_helper(int in); +dof_helper_t *usdt_copyin_helper(int in); /* - * Get a buffer of DOF from the input fd and sanity-check it. + * Get a USDT data block from the input fd. * * Set OK to zero if no further parsing is possible. */ -dof_hdr_t *dof_copyin_dof(int in, int out, int *ok); +usdt_data_t *usdt_copyin_data(int in, int out, int *ok); /* - * Parse probe info out of the passed-in dof_helper_t and dof_hdr_t DOF buffer, - * and pass it out of OUT in the form of a stream of dof_parser_info_t. + * Parse probe info out of the passed-in dof_helper_t and USDT definitions data + * block and emit it to OUT in the form of a stream of dof_parser_info_t. */ -void dof_parse(int out, dof_helper_t *dhp, dof_hdr_t *dof); +void usdt_parse(int out, dof_helper_t *dhp, usdt_data_t *data); + +/* + * Parse probe info out of the passed-in dof_helper_t and DOF section data and + * emit it to OUT in the form of a stream of dof_parser_info_t. + * + * Returns 0 on success or a positive errno value on error. + */ +int usdt_parse_dof(int out, dof_helper_t *dhp, dof_hdr_t *dof); /* * Shared host and parser-side. */ + /* * Write something to the parser pipe OUT. * * Returns 0 on success or a positive errno value on error. */ -int dof_parser_write_one(int out, const void *buf, size_t size); +int usdt_parser_write_one(int out, const void *buf, size_t size); -#endif /* _DOF_PARSER_H */ +#endif /* _USDT_PARSER_H */ diff --git a/libcommon/dof_parser.c b/libcommon/usdt_parser_dof.c similarity index 68% rename from libcommon/dof_parser.c rename to libcommon/usdt_parser_dof.c index ec80cee8..6a7eb377 100644 --- a/libcommon/dof_parser.c +++ b/libcommon/usdt_parser_dof.c @@ -1,6 +1,6 @@ /* - * Oracle Linux DTrace; DOF parser. - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Oracle Linux DTrace; USDT definitions parser - DOF. + * 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. */ @@ -15,12 +15,11 @@ #include #include #include -#include "dof_parser.h" +#include +#include "usdt_parser.h" #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) -size_t dof_maxsize = 256 * 1024 * 1024; - typedef struct dtrace_helper_probedesc { char *dthpb_prov; char *dthpb_mod; @@ -48,144 +47,9 @@ static void dt_dbg_dof(const char *fmt, ...) #endif } -_dt_printflike_(3, 4) -static void dof_error(int out, int err_no, const char *fmt, ...) -{ - dof_parsed_t *parsed; - size_t sz; - char *msg; - va_list ap; - - /* - * Not much we can do on OOM of errors other than abort, forcing a - * parser restart, which hopefully will have enough memory to report the - * error properly. - */ - va_start(ap, fmt); - if (vasprintf(&msg, fmt, ap) < 0) - abort(); - va_end(ap); - - sz = offsetof(dof_parsed_t, err.err) + strlen(msg) + 1; - parsed = malloc(sz); - - if (!parsed) - abort(); - - memset(parsed, 0, sz); - parsed->size = sz; - parsed->type = DIT_ERR; - parsed->err.err_no = err_no; - strcpy(parsed->err.err, msg); - - dof_parser_write_one(out, parsed, parsed->size); - free(parsed); - free(msg); -} - -static char * -dof_copyin(int in, char *buf_, size_t sz) -{ - char *buf = buf_; - size_t i; - - if (!buf) { - buf = malloc(sz); - if (!buf) - abort(); - } - - memset(buf, 0, sz); - - for (i = 0; i < sz; ) { - size_t ret; - - ret = read(in, buf + i, sz - i); - - if (ret < 0) { - switch (errno) { - case EINTR: - continue; - default: - goto err; - } - } - - /* - * EOF: parsing done, process shutting down or message - * truncated. Fail, in any case. - */ - if (ret == 0) - goto err; - - i += ret; - } - - return buf; - -err: - if (!buf_) - free(buf); - return NULL; -} - -dof_helper_t * -dof_copyin_helper(int in) -{ - return (dof_helper_t *)dof_copyin(in, NULL, sizeof(dof_helper_t)); -} - -dof_hdr_t * -dof_copyin_dof(int in, int out, int *ok) -{ - dof_hdr_t *dof; - - *ok = 1; - - /* First get the header, which gives the size of everything else. */ - dof = (dof_hdr_t *)dof_copyin(in, NULL, sizeof(dof_hdr_t)); - if (!dof) - abort(); - - /* Validate the DOF load size. */ - if (dof->dofh_loadsz >= dof_maxsize) { - dof_error(out, E2BIG, "load size %zi exceeds maximum %zi", - dof->dofh_loadsz, dof_maxsize); - return NULL; - } - - if (dof->dofh_loadsz < sizeof(dof_hdr_t)) { - dof_error(out, EINVAL, "invalid load size %zi, " - "smaller than header size %zi", dof->dofh_loadsz, - sizeof(dof_hdr_t)); - return NULL; - } - - /* Resize the allocated memory to fit the actual data as well. */ - dof = realloc(dof, dof->dofh_loadsz); - if (!dof) - abort(); - - /* Read the actual data in the allocated buffer. */ - if (!dof_copyin(in, ((char *)dof) + sizeof(dof_hdr_t), - dof->dofh_loadsz - sizeof(dof_hdr_t))) { - *ok = 0; - free(dof); - return NULL; - } - - return dof; -} - -static void dof_destroy(dof_helper_t *dhp, dof_hdr_t *dof) -{ - free(dhp); - free(dof); -} - /* * Return the dof_sec_t pointer corresponding to a given section index. If the - * index is not valid, dof_error() is called and NULL is returned. If a type + * index is not valid, usdt_error() is called and NULL is returned. If a type * other than DOF_SECT_NONE is specified, the header is checked against this * type and NULL is returned if the types do not match. */ @@ -199,19 +63,19 @@ static dof_sec_t *dof_sect(int out, dof_hdr_t *dof, i * dof->dofh_secsize); if (i >= dof->dofh_secnum) { - dof_error(out, EINVAL, "referenced section index %u is " - "invalid, above %u", i, dof->dofh_secnum); + usdt_error(out, EINVAL, "referenced section index %u is " + "invalid, above %u", i, dof->dofh_secnum); return NULL; } if (!(sec->dofs_flags & DOF_SECF_LOAD)) { - dof_error(out, EINVAL, "referenced section %u is not loadable", i); + usdt_error(out, EINVAL, "referenced section %u is not loadable", i); return NULL; } if (sectype != DOF_SECT_NONE && sectype != sec->dofs_type) { - dof_error(out, EINVAL, "referenced section %u is the wrong type, " - "%u, not %u", i, sec->dofs_type, sectype); + usdt_error(out, EINVAL, "referenced section %u is the wrong type, " + "%u, not %u", i, sec->dofs_type, sectype); return NULL; } @@ -237,10 +101,10 @@ dof_relocate(int out, dof_hdr_t *dof, dof_sec_t *sec, uint64_t ubase) if (sec->dofs_size < sizeof(dof_relohdr_t) || sec->dofs_align != sizeof(dof_secidx_t)) { - dof_error(out, EINVAL, "invalid relocation header: " - "size %zi (expected %zi); alignment %u (expected %zi)", - sec->dofs_size, sizeof(dof_relohdr_t), - sec->dofs_align, sizeof(dof_secidx_t)); + usdt_error(out, EINVAL, "invalid relocation header: " + "size %zi (expected %zi); alignment %u (expected %zi)", + sec->dofs_size, sizeof(dof_relohdr_t), + sec->dofs_align, sizeof(dof_secidx_t)); return -1; } @@ -249,14 +113,14 @@ dof_relocate(int out, dof_hdr_t *dof, dof_sec_t *sec, uint64_t ubase) ts = dof_sect(out, dof, DOF_SECT_NONE, dofr->dofr_tgtsec); if (ss == NULL || rs == NULL || ts == NULL) - return -1; /* dof_error() has been called already */ + return -1; /* usdt_error() has been called already */ if (rs->dofs_entsize < sizeof(dof_relodesc_t) || rs->dofs_align != sizeof(uint64_t)) { - dof_error(out, EINVAL, "invalid relocation section: entsize %i " - "(expected %zi); alignment %u (expected %zi)", - rs->dofs_entsize, sizeof(dof_relodesc_t), - rs->dofs_align, sizeof(uint64_t)); + usdt_error(out, EINVAL, "invalid relocation section: entsize %i " + "(expected %zi); alignment %u (expected %zi)", + rs->dofs_entsize, sizeof(dof_relodesc_t), + rs->dofs_align, sizeof(uint64_t)); return -1; } @@ -273,14 +137,14 @@ dof_relocate(int out, dof_hdr_t *dof, dof_sec_t *sec, uint64_t ubase) if (r->dofr_offset >= ts->dofs_size || r->dofr_offset + sizeof(uint64_t) > ts->dofs_size) { - dof_error(out, EINVAL, "bad relocation offset: " - "offset %zi, section size %zi)", - r->dofr_offset, ts->dofs_size); + usdt_error(out, EINVAL, "bad relocation offset: " + "offset %zi, section size %zi)", + r->dofr_offset, ts->dofs_size); return -1; } if (!IS_ALIGNED(taddr, sizeof(uint64_t))) { - dof_error(out, EINVAL, "misaligned setx relo"); + usdt_error(out, EINVAL, "misaligned setx relo"); return -1; } @@ -306,8 +170,8 @@ dof_relocate(int out, dof_hdr_t *dof, dof_sec_t *sec, uint64_t ubase) break; default: - dof_error(out, EINVAL, "invalid relocation type %i", - r->dofr_type); + usdt_error(out, EINVAL, "invalid relocation type %i", + r->dofr_type); return -1; } @@ -331,8 +195,8 @@ dof_slurp(int out, dof_hdr_t *dof, uint64_t ubase) uint_t i; if (_dt_unlikely_(dof->dofh_loadsz < sizeof(dof_hdr_t))) { - dof_error(out, EINVAL, "load size %zi smaller than header %zi", - dof->dofh_loadsz, sizeof(dof_hdr_t)); + usdt_error(out, EINVAL, "load size %zi smaller than header %zi", + dof->dofh_loadsz, sizeof(dof_hdr_t)); return -1; } @@ -347,72 +211,72 @@ dof_slurp(int out, dof_hdr_t *dof, uint64_t ubase) */ if (memcmp(&dof->dofh_ident[DOF_ID_MAG0], DOF_MAG_STRING, DOF_MAG_STRLEN) != 0) { - dof_error(out, EINVAL, "DOF magic string mismatch: %c%c%c%c " - "versus %c%c%c%c\n", dof->dofh_ident[DOF_ID_MAG0], - dof->dofh_ident[DOF_ID_MAG1], - dof->dofh_ident[DOF_ID_MAG2], - dof->dofh_ident[DOF_ID_MAG3], - DOF_MAG_STRING[0], - DOF_MAG_STRING[1], - DOF_MAG_STRING[2], - DOF_MAG_STRING[3]); + usdt_error(out, EINVAL, "DOF magic string mismatch: %c%c%c%c " + "versus %c%c%c%c\n", dof->dofh_ident[DOF_ID_MAG0], + dof->dofh_ident[DOF_ID_MAG1], + dof->dofh_ident[DOF_ID_MAG2], + dof->dofh_ident[DOF_ID_MAG3], + DOF_MAG_STRING[0], + DOF_MAG_STRING[1], + DOF_MAG_STRING[2], + DOF_MAG_STRING[3]); return -1; } if (dof->dofh_ident[DOF_ID_MODEL] != DOF_MODEL_ILP32 && dof->dofh_ident[DOF_ID_MODEL] != DOF_MODEL_LP64) { - dof_error(out, EINVAL, "DOF has invalid data model: %i", - dof->dofh_ident[DOF_ID_MODEL]); + usdt_error(out, EINVAL, "DOF has invalid data model: %i", + dof->dofh_ident[DOF_ID_MODEL]); return -1; } if (dof->dofh_ident[DOF_ID_ENCODING] != DOF_ENCODE_NATIVE) { - dof_error(out, EINVAL, "DOF encoding mismatch: %i, expected %i", - dof->dofh_ident[DOF_ID_ENCODING], DOF_ENCODE_NATIVE); + usdt_error(out, EINVAL, "DOF encoding mismatch: %i, expected %i", + dof->dofh_ident[DOF_ID_ENCODING], DOF_ENCODE_NATIVE); return -1; } if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_2 && dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_3) { - dof_error(out, EINVAL, "DOF version mismatch: %i", - dof->dofh_ident[DOF_ID_VERSION]); + usdt_error(out, EINVAL, "DOF version mismatch: %i", + dof->dofh_ident[DOF_ID_VERSION]); return -1; } if (dof->dofh_ident[DOF_ID_DIFVERS] != DIF_VERSION_2) { - dof_error(out, EINVAL, "DOF uses unsupported instruction set %i", - dof->dofh_ident[DOF_ID_DIFVERS]); + usdt_error(out, EINVAL, "DOF uses unsupported instruction set %i", + dof->dofh_ident[DOF_ID_DIFVERS]); return -1; } if (dof->dofh_ident[DOF_ID_DIFIREG] > DIF_DIR_NREGS) { - dof_error(out, EINVAL, "DOF uses too many integer registers: %i > %i", - dof->dofh_ident[DOF_ID_DIFIREG], DIF_DIR_NREGS); + usdt_error(out, EINVAL, "DOF uses too many integer registers: %i > %i", + dof->dofh_ident[DOF_ID_DIFIREG], DIF_DIR_NREGS); return -1; } if (dof->dofh_ident[DOF_ID_DIFTREG] > DIF_DTR_NREGS) { - dof_error(out, EINVAL, "DOF uses too many tuple registers: %i > %i", - dof->dofh_ident[DOF_ID_DIFTREG], DIF_DTR_NREGS); + usdt_error(out, EINVAL, "DOF uses too many tuple registers: %i > %i", + dof->dofh_ident[DOF_ID_DIFTREG], DIF_DTR_NREGS); return -1; } for (i = DOF_ID_PAD; i < DOF_ID_SIZE; i++) { if (dof->dofh_ident[i] != 0) { - dof_error(out, EINVAL, "DOF has invalid ident byte set: %i = %i", - i, dof->dofh_ident[i]); + usdt_error(out, EINVAL, "DOF has invalid ident byte set: %i = %i", + i, dof->dofh_ident[i]); return -1; } } if (dof->dofh_flags & ~DOF_FL_VALID) { - dof_error(out, EINVAL, "DOF has invalid flag bits set: %xi", dof->dofh_flags); + usdt_error(out, EINVAL, "DOF has invalid flag bits set: %xi", dof->dofh_flags); return -1; } if (dof->dofh_secsize == 0) { - dof_error(out, EINVAL, "zero section header size"); + usdt_error(out, EINVAL, "zero section header size"); return -1; } @@ -425,18 +289,18 @@ dof_slurp(int out, dof_hdr_t *dof, uint64_t ubase) if (dof->dofh_secoff > len || seclen > len || dof->dofh_secoff + seclen > len) { - dof_error(out, EINVAL, "truncated section headers: %zi, %zi, %zi", - dof->dofh_secoff, len, seclen); + usdt_error(out, EINVAL, "truncated section headers: %zi, %zi, %zi", + dof->dofh_secoff, len, seclen); return -1; } if (!IS_ALIGNED(dof->dofh_secoff, sizeof(uint64_t))) { - dof_error(out, EINVAL, "misaligned section headers"); + usdt_error(out, EINVAL, "misaligned section headers"); return -1; } if (!IS_ALIGNED(dof->dofh_secsize, sizeof(uint64_t))) { - dof_error(out, EINVAL, "misaligned section size"); + usdt_error(out, EINVAL, "misaligned section size"); return -1; } @@ -454,8 +318,8 @@ dof_slurp(int out, dof_hdr_t *dof, uint64_t ubase) if (DOF_SEC_ISLOADABLE(sec->dofs_type) && !(sec->dofs_flags & DOF_SECF_LOAD)) { - dof_error(out, EINVAL, "loadable section %i with load flag unset", - i); + usdt_error(out, EINVAL, "loadable section %i with load flag unset", + i); return -1; } @@ -466,30 +330,30 @@ dof_slurp(int out, dof_hdr_t *dof, uint64_t ubase) continue; if (sec->dofs_align & (sec->dofs_align - 1)) { - dof_error(out, EINVAL, "bad section %i alignment %x", i, - sec->dofs_align); + usdt_error(out, EINVAL, "bad section %i alignment %x", + i, sec->dofs_align); return -1; } if (sec->dofs_offset & (sec->dofs_align - 1)) { - dof_error(out, EINVAL, "misaligned section %i: %lx, " - "stated alignment %xi", i, sec->dofs_offset, - sec->dofs_align); + usdt_error(out, EINVAL, "misaligned section %i: %lx, " + "stated alignment %xi", i, sec->dofs_offset, + sec->dofs_align); return -1; } if (sec->dofs_offset > len || sec->dofs_size > len || sec->dofs_offset + sec->dofs_size > len) { - dof_error(out, EINVAL, "corrupt section %i header: " - "offset %lx, size %lx, len %lx", i, - sec->dofs_offset, sec->dofs_size, len); + usdt_error(out, EINVAL, "corrupt section %i header: " + "offset %lx, size %lx, len %lx", i, + sec->dofs_offset, sec->dofs_size, len); return -1; } if (sec->dofs_type == DOF_SECT_STRTAB && *((char *)daddr + sec->dofs_offset + sec->dofs_size - 1) != '\0') { - dof_error(out, EINVAL, "section %i: non-0-terminated " - "string table", i); + usdt_error(out, EINVAL, "section %i: non-0-terminated " + "string table", i); return -1; } } @@ -540,13 +404,13 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec) uint_t nprobes, j, k; if (_dt_unlikely_(sec->dofs_type != DOF_SECT_PROVIDER)) { - dof_error(out, EINVAL, "DOF is not provider DOF: %i", sec->dofs_type); + usdt_error(out, EINVAL, "DOF is not provider DOF: %i", sec->dofs_type); return -1; } if (sec->dofs_offset & (sizeof(uint_t) - 1)) { - dof_error(out, EINVAL, "misaligned section offset: %lx", - sec->dofs_offset); + usdt_error(out, EINVAL, "misaligned section offset: %lx", + sec->dofs_offset); return -1; } @@ -558,8 +422,8 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec) ((dof->dofh_ident[DOF_ID_VERSION] == DOF_VERSION_1) ? offsetof(dof_provider_t, dofpv_prenoffs) : sizeof(dof_provider_t))) { - dof_error(out, EINVAL, "provider section too small: %lx", - sec->dofs_size); + usdt_error(out, EINVAL, "provider section too small: %lx", + sec->dofs_size); return -1; } @@ -587,45 +451,45 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec) strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); if (prov->dofpv_name >= str_sec->dofs_size) { - dof_error(out, EINVAL, "invalid provider name offset: %u > %zi", - prov->dofpv_name, str_sec->dofs_size); + usdt_error(out, EINVAL, "invalid provider name offset: %u > %zi", + prov->dofpv_name, str_sec->dofs_size); return -1; } if (strlen(strtab + prov->dofpv_name) >= DTRACE_PROVNAMELEN) { - dof_error(out, EINVAL, "provider name too long: %s", - strtab + prov->dofpv_name); + usdt_error(out, EINVAL, "provider name too long: %s", + strtab + prov->dofpv_name); return -1; } if (prb_sec->dofs_entsize == 0 || prb_sec->dofs_entsize > prb_sec->dofs_size) { - dof_error(out, EINVAL, "invalid entry size %x, max %lx", - prb_sec->dofs_entsize, prb_sec->dofs_size); + usdt_error(out, EINVAL, "invalid entry size %x, max %lx", + prb_sec->dofs_entsize, prb_sec->dofs_size); return -1; } if (prb_sec->dofs_entsize & (sizeof(uintptr_t) - 1)) { - dof_error(out, EINVAL, "misaligned entry size %x", - prb_sec->dofs_entsize); + usdt_error(out, EINVAL, "misaligned entry size %x", + prb_sec->dofs_entsize); return -1; } if (off_sec->dofs_entsize != sizeof(uint32_t)) { - dof_error(out, EINVAL, "invalid entry size %x", - off_sec->dofs_entsize); + usdt_error(out, EINVAL, "invalid entry size %x", + off_sec->dofs_entsize); return -1; } if (off_sec->dofs_offset & (sizeof(uint32_t) - 1)) { - dof_error(out, EINVAL, "misaligned section offset %lx", - off_sec->dofs_offset); + usdt_error(out, EINVAL, "misaligned section offset %lx", + off_sec->dofs_offset); return -1; } if (arg_sec->dofs_entsize != sizeof(uint8_t)) { - dof_error(out, EINVAL, "invalid entry size %x", - arg_sec->dofs_entsize); + usdt_error(out, EINVAL, "invalid entry size %x", + arg_sec->dofs_entsize); return -1; } @@ -644,28 +508,28 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec) j * prb_sec->dofs_entsize); if (prb->dofpr_func >= str_sec->dofs_size) { - dof_error(out, EINVAL, "invalid function name: " - "strtab offset %x, max %lx", prb->dofpr_func, - str_sec->dofs_size); + usdt_error(out, EINVAL, "invalid function name: " + "strtab offset %x, max %lx", prb->dofpr_func, + str_sec->dofs_size); return -1; } if (strlen(strtab + prb->dofpr_func) >= DTRACE_FUNCNAMELEN) { - dof_error(out, EINVAL, "function name %s too long", - strtab + prb->dofpr_func); + usdt_error(out, EINVAL, "function name %s too long", + strtab + prb->dofpr_func); return -1; } if (prb->dofpr_name >= str_sec->dofs_size) { - dof_error(out, EINVAL, "invalid probe name: " - "strtab offset %x, max %lx", prb->dofpr_name, - str_sec->dofs_size); + usdt_error(out, EINVAL, "invalid probe name: " + "strtab offset %x, max %lx", prb->dofpr_name, + str_sec->dofs_size); return -1; } if (strlen(strtab + prb->dofpr_name) >= DTRACE_NAMELEN) { - dof_error(out, EINVAL, "probe name %s too long", - strtab + prb->dofpr_name); + usdt_error(out, EINVAL, "probe name %s too long", + strtab + prb->dofpr_name); return -1; } @@ -676,10 +540,10 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec) if (prb->dofpr_offidx + prb->dofpr_noffs < prb->dofpr_offidx || (prb->dofpr_offidx + prb->dofpr_noffs) * off_sec->dofs_entsize > off_sec->dofs_size) { - dof_error(out, EINVAL, "invalid probe offset %x " - "(offset count %x, section entsize %x, size %lx)", - prb->dofpr_offidx, prb->dofpr_noffs, - off_sec->dofs_entsize, off_sec->dofs_size); + usdt_error(out, EINVAL, "invalid probe offset %x " + "(offset count %x, section entsize %x, size %lx)", + prb->dofpr_offidx, prb->dofpr_noffs, + off_sec->dofs_entsize, off_sec->dofs_size); return -1; } @@ -693,8 +557,8 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec) if (enoff_sec == NULL) { if (prb->dofpr_enoffidx != 0 || prb->dofpr_nenoffs != 0) { - dof_error(out, EINVAL, - "is-enabled offsets with null section"); + usdt_error(out, EINVAL, + "is-enabled offsets with null section"); return -1; } } else if (prb->dofpr_enoffidx + prb->dofpr_nenoffs < @@ -702,29 +566,29 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec) (prb->dofpr_enoffidx + prb->dofpr_nenoffs) * enoff_sec->dofs_entsize > enoff_sec->dofs_size) { - dof_error(out, EINVAL, "invalid is-enabled offset %x " - "(offset count %x, section entsize %x, size %lx)", - prb->dofpr_enoffidx, prb->dofpr_nenoffs, - enoff_sec->dofs_entsize, enoff_sec->dofs_size); + usdt_error(out, EINVAL, "invalid is-enabled offset %x " + "(offset count %x, section entsize %x, size %lx)", + prb->dofpr_enoffidx, prb->dofpr_nenoffs, + enoff_sec->dofs_entsize, enoff_sec->dofs_size); return -1; } if (prb->dofpr_noffs + prb->dofpr_nenoffs == 0) { - dof_error(out, EINVAL, "zero probe and is-enabled offsets"); + usdt_error(out, EINVAL, "zero probe and is-enabled offsets"); return -1; } } else if (prb->dofpr_noffs == 0) { - dof_error(out, EINVAL, "zero probe offsets"); + usdt_error(out, EINVAL, "zero probe offsets"); return -1; } if (prb->dofpr_argidx + prb->dofpr_xargc < prb->dofpr_argidx || (prb->dofpr_argidx + prb->dofpr_xargc) * arg_sec->dofs_entsize > arg_sec->dofs_size) { - dof_error(out, EINVAL, "invalid args, idx %x " - "(offset count %x, section entsize %x, size %lx)", - prb->dofpr_argidx, prb->dofpr_xargc, - arg_sec->dofs_entsize, arg_sec->dofs_size); + usdt_error(out, EINVAL, "invalid args, idx %x " + "(offset count %x, section entsize %x, size %lx)", + prb->dofpr_argidx, prb->dofpr_xargc, + arg_sec->dofs_entsize, arg_sec->dofs_size); return -1; } @@ -732,15 +596,15 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec) typestr = strtab + prb->dofpr_nargv; for (k = 0; k < prb->dofpr_nargc; k++) { if (typeidx >= str_sec->dofs_size) { - dof_error(out, EINVAL, "bad native argument type " - "for arg %i: %x", k, typeidx); + usdt_error(out, EINVAL, "bad native argument type " + "for arg %i: %x", k, typeidx); return -1; } typesz = strlen(typestr) + 1; if (typesz > DTRACE_ARGTYPELEN) { - dof_error(out, EINVAL, "native argument type for arg %i " - "too long: %s", k, typestr); + usdt_error(out, EINVAL, "native argument type for arg %i " + "too long: %s", k, typestr); return -1; } @@ -752,23 +616,23 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec) typestr = strtab + prb->dofpr_xargv; for (k = 0; k < prb->dofpr_xargc; k++) { if (arg[prb->dofpr_argidx + k] > prb->dofpr_nargc) { - dof_error(out, EINVAL, "bad native argument index " - "for arg %i: %i (max %i)", k, - arg[prb->dofpr_argidx + k], - prb->dofpr_nargc); + usdt_error(out, EINVAL, "bad native argument index " + "for arg %i: %i (max %i)", k, + arg[prb->dofpr_argidx + k], + prb->dofpr_nargc); return -1; } if (typeidx >= str_sec->dofs_size) { - dof_error(out, EINVAL, "bad translated argument type " - "for arg %i: %x", k, typeidx); + usdt_error(out, EINVAL, "bad translated argument type " + "for arg %i: %x", k, typeidx); return -1; } typesz = strlen(typestr) + 1; if (typesz > DTRACE_ARGTYPELEN) { - dof_error(out, EINVAL, "translated argument type for arg %i " - "too long: %s", k, typestr); + usdt_error(out, EINVAL, "translated argument type for arg %i " + "too long: %s", k, typestr); return -1; } @@ -798,7 +662,7 @@ emit_tp(int out, uint64_t base, uint64_t offs, int is_enabled) tp.type = DIT_TRACEPOINT; tp.tracepoint.addr = base + offs; tp.tracepoint.is_enabled = is_enabled; - dof_parser_write_one(out, &tp, tp.size); + usdt_parser_write_one(out, &tp, tp.size); dt_dbg_dof(" Tracepoint at 0x%lx (0x%llx + 0x%x)%s\n", base + offs, base, offs, is_enabled ? " (is_enabled)" : ""); @@ -823,9 +687,9 @@ validate_probe(int out, dtrace_helper_probedesc_t *dhpb) for (i = 1; i < dhpb->dthpb_noffs; i++) { if (dhpb->dthpb_base + dhpb->dthpb_offs[i] <= dhpb->dthpb_base + dhpb->dthpb_offs[i - 1]) { - dof_error(out, EINVAL, "non-unique USDT offsets at %i: %li <= %li", - i, dhpb->dthpb_base + dhpb->dthpb_offs[i], - dhpb->dthpb_base + dhpb->dthpb_offs[i - 1]); + usdt_error(out, EINVAL, "non-unique USDT offsets at %i: %li <= %li", + i, dhpb->dthpb_base + dhpb->dthpb_offs[i], + dhpb->dthpb_base + dhpb->dthpb_offs[i - 1]); return -1; } } @@ -835,16 +699,16 @@ validate_probe(int out, dtrace_helper_probedesc_t *dhpb) for (i = 1; i < dhpb->dthpb_nenoffs; i++) { if (dhpb->dthpb_base + dhpb->dthpb_enoffs[i] <= dhpb->dthpb_base + dhpb->dthpb_enoffs[i - 1]) { - dof_error(out, EINVAL, "non-unique is-enabled USDT offsets " - "at %i: %li <= %li", i, - dhpb->dthpb_base + dhpb->dthpb_enoffs[i], - dhpb->dthpb_base + dhpb->dthpb_enoffs[i - 1]); + usdt_error(out, EINVAL, "non-unique is-enabled USDT offsets " + "at %i: %li <= %li", i, + dhpb->dthpb_base + dhpb->dthpb_enoffs[i], + dhpb->dthpb_base + dhpb->dthpb_enoffs[i - 1]); return -1; } } if (dhpb->dthpb_noffs == 0 && dhpb->dthpb_nenoffs == 0) { - dof_error(out, EINVAL, "USDT probe with zero tracepoints"); + usdt_error(out, EINVAL, "USDT probe with zero tracepoints"); return -1; } return 0; @@ -905,7 +769,7 @@ emit_probe(int out, dtrace_helper_probedesc_t *dhpb) ptr = stpcpy(ptr, dhpb->dthpb_func); ptr++; strcpy(ptr, dhpb->dthpb_name); - dof_parser_write_one(out, msg, msg_size); + usdt_parser_write_one(out, msg, msg_size); free(msg); @@ -932,7 +796,7 @@ emit_probe(int out, dtrace_helper_probedesc_t *dhpb) msg->size = msg_size; msg->type = DIT_ARGS_NATIVE; memcpy(msg->nargs.args, dhpb->dthpb_ntypes, nargs_size); - dof_parser_write_one(out, msg, msg_size); + usdt_parser_write_one(out, msg, msg_size); free(msg); @@ -955,7 +819,7 @@ emit_probe(int out, dtrace_helper_probedesc_t *dhpb) msg->size = msg_size; msg->type = DIT_ARGS_XLAT; memcpy(msg->xargs.args, dhpb->dthpb_xtypes, xargs_size); - dof_parser_write_one(out, msg, msg_size); + usdt_parser_write_one(out, msg, msg_size); free(msg); @@ -974,7 +838,7 @@ emit_probe(int out, dtrace_helper_probedesc_t *dhpb) msg->size = msg_size; msg->type = DIT_ARGS_MAP; memcpy(msg->argmap.argmap, dhpb->dthpb_args, map_size); - dof_parser_write_one(out, msg, msg_size); + usdt_parser_write_one(out, msg, msg_size); free(msg); } } @@ -996,8 +860,8 @@ emit_probe(int out, dtrace_helper_probedesc_t *dhpb) return; oom: - dof_error(out, ENOMEM, "Out of memory allocating %zi bytes for probe", - msg_size); + usdt_error(out, ENOMEM, "Out of memory allocating %zi bytes for probe", + msg_size); } static void @@ -1062,7 +926,7 @@ emit_provider(int out, dof_helper_t *dhp, provider_msg = malloc(provider_msg_size); if (!provider_msg) { - dof_error(out, ENOMEM, "Out of memory allocating probe"); + usdt_error(out, ENOMEM, "Out of memory allocating probe"); return; } memset(provider_msg, 0, provider_msg_size); @@ -1071,7 +935,7 @@ emit_provider(int out, dof_helper_t *dhp, provider_msg->type = DIT_PROVIDER; provider_msg->provider.nprobes = prb_sec->dofs_size / prb_sec->dofs_entsize; strcpy(provider_msg->provider.name, dhpb.dthpb_prov); - dof_parser_write_one(out, provider_msg, provider_msg_size); + usdt_parser_write_one(out, provider_msg, provider_msg_size); /* * Pass back info on the probes and their associated tracepoints. @@ -1110,21 +974,24 @@ emit_provider(int out, dof_helper_t *dhp, free(provider_msg); } -void -dof_parse(int out, dof_helper_t *dhp, dof_hdr_t *dof) +int +usdt_parse_dof(int out, dof_helper_t *dhp, dof_hdr_t *dof) { - int i, rv; - uintptr_t daddr = (uintptr_t)dof; - dof_parsed_t eof; + int i; + uintptr_t daddr = (uintptr_t)dof; + + if (dof->dofh_loadsz < sizeof(dof_hdr_t)) { + usdt_error(out, EINVAL, "invalid load size %zi, " + "smaller than header size %zi", + dof->dofh_loadsz, sizeof(dof_hdr_t)); + return -1; + } dt_dbg_dof("DOF 0x%p from helper {'%s', %p, %p}...\n", dof, dhp ? dhp->dofhp_mod : "", dhp, dof); - rv = dof_slurp(out, dof, dhp->dofhp_addr); - if (rv != 0) { - dof_destroy(dhp, dof); - return; - } + if (dof_slurp(out, dof, dhp->dofhp_addr) != 0) + return -1; /* * Look for providers, validate their descriptions, and parse them. @@ -1142,23 +1009,12 @@ dof_parse(int out, dof_helper_t *dhp, dof_hdr_t *dof) if (sec->dofs_type != DOF_SECT_PROVIDER) continue; - if (validate_provider(out, dof, sec) != 0) { - dof_destroy(dhp, dof); - return; - } + if (validate_provider(out, dof, sec) != 0) + return -1; + emit_provider(out, dhp, dof, sec); } } - /* - * Always emit an EOF, to wake up the caller if nothing else, but also - * to notify the caller that there are no more providers to read. - */ - memset(&eof, 0, sizeof(dof_parsed_t)); - - eof.size = offsetof(dof_parsed_t, provider.nprobes); - eof.type = DIT_EOF; - dof_parser_write_one(out, &eof, eof.size); - - dof_destroy(dhp, dof); + return 0; } diff --git a/libcommon/dof_parser_host.c b/libcommon/usdt_parser_host.c similarity index 71% rename from libcommon/dof_parser_host.c rename to libcommon/usdt_parser_host.c index 5a7546af..2e824635 100644 --- a/libcommon/dof_parser_host.c +++ b/libcommon/usdt_parser_host.c @@ -1,6 +1,6 @@ /* - * Oracle Linux DTrace; DOF-consumption and USDT-probe-creation daemon. - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Oracle Linux DTrace; Host-parser communication implementation. + * Copyright (c) 2022, 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. */ @@ -12,8 +12,8 @@ #include #include #include - -#include "dof_parser.h" +#include +#include "usdt_parser.h" /* * Write BUF to the parser pipe OUT. @@ -21,7 +21,7 @@ * Returns 0 on success or a positive errno value on error. */ int -dof_parser_write_one(int out, const void *buf_, size_t size) +usdt_parser_write_one(int out, const void *buf_, size_t size) { size_t i; char *buf = (char *) buf_; @@ -51,26 +51,46 @@ dof_parser_write_one(int out, const void *buf_, size_t size) * Returns 0 on success or a positive errno value on error. */ int -dof_parser_host_write(int out, const dof_helper_t *dh, dof_hdr_t *dof) +usdt_parser_host_write(int out, const dof_helper_t *dh, const usdt_data_t *data) { int err; + size_t cnt = 0; + const usdt_data_t *blk; + + /* Write dof_helper_t structure. */ + if ((err = usdt_parser_write_one(out, (const char *)dh, + sizeof(*dh))) < 0) + return err; + + /* Count and write nunmber of blocks that follow. */ + for (blk = data; blk != NULL; blk = blk->next) + cnt++; - if ((err = dof_parser_write_one(out, (const char *)dh, - sizeof(dof_helper_t))) < 0) + if ((err = usdt_parser_write_one(out, (const char *)&cnt, + sizeof(cnt))) < 0) return err; - return dof_parser_write_one(out, (const char *)dof, - dof->dofh_loadsz); + /* Write the blocks (for each, size followed by data). */ + for (blk = data; blk != NULL; blk = blk->next) { + if ((err = usdt_parser_write_one(out, (const char *)&blk->size, + sizeof(blk->size))) < 0) + return err; + if ((err = usdt_parser_write_one(out, (const char *)blk->buf, + blk->size)) < 0) + return err; + } + + return 0; } /* - * Read a single DOF structure from a parser pipe. Wait at most TIMEOUT seconds - * to do so. + * Read a single dof_parsed_t structure from a parser pipe. Wait at most + * TIMEOUT seconds to do so. * * Returns NULL and sets errno on error. */ dof_parsed_t * -dof_parser_host_read(int in, int timeout) +usdt_parser_host_read(int in, int timeout) { size_t i, sz; dof_parsed_t *reply; diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index 4aa94d81..9b1a2278 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -30,7 +30,7 @@ #endif #include -#include +#include #include #include -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:01 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:01 -0400 Subject: [DTrace-devel] [PATCH 09/17] htab: move htab handling to libcommon Message-ID: Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock --- libcommon/Build | 3 ++- {libdtrace => libcommon}/dt_htab.c | 19 +++++++++---------- {libdtrace => libcommon}/dt_htab.h | 8 +++----- libdtrace/Build | 1 - libdtrace/dt_consume.c | 4 ++-- libdtrace/dt_kernel_module.c | 4 ++-- libdtrace/dt_module.c | 2 +- libdtrace/dt_open.c | 10 +++++----- libdtrace/dt_probe.c | 22 +++++++++++----------- libdtrace/dt_provider.c | 4 ++-- libdtrace/dt_symtab.c | 2 +- 11 files changed, 38 insertions(+), 41 deletions(-) rename {libdtrace => libcommon}/dt_htab.c (95%) rename {libdtrace => libcommon}/dt_htab.h (91%) diff --git a/libcommon/Build b/libcommon/Build index f64545ed..6237351f 100644 --- a/libcommon/Build +++ b/libcommon/Build @@ -9,7 +9,8 @@ LIBS += libcommon libcommon_TARGET = libcommon libcommon_DIR := $(current-dir) libcommon_CPPFLAGS := -Ilibcommon -Ilibproc -U_FORTIFY_SOURCE -libcommon_SOURCES = usdt_parser.c usdt_parser_dof.c usdt_parser_host.c dt_list.c +libcommon_SOURCES = dt_htab.c dt_list.c \ + usdt_parser.c usdt_parser_dof.c usdt_parser_host.c libcommon_NOCFLAGS := -D_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -D_FORTIFY_SOURCE=2 -D_FORTIFY_SOURCE=3 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=1 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=2 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 libcommon_NOCPPFLAGS := -D_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -D_FORTIFY_SOURCE=2 -D_FORTIFY_SOURCE=3 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=1 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=2 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 libcommon_LIBSOURCES = libcommon diff --git a/libdtrace/dt_htab.c b/libcommon/dt_htab.c similarity index 95% rename from libdtrace/dt_htab.c rename to libcommon/dt_htab.c index 478c728a..43782202 100644 --- a/libdtrace/dt_htab.c +++ b/libcommon/dt_htab.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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. */ @@ -28,8 +28,7 @@ #include #include #include - -#include "dt_impl.h" +#include typedef struct dt_hbucket dt_hbucket_t; struct dt_hbucket { @@ -66,9 +65,9 @@ struct dt_htab_next { /* * Create a new (empty) hashtable. */ -dt_htab_t *dt_htab_create(dtrace_hdl_t *dtp, dt_htab_ops_t *ops) +dt_htab_t *dt_htab_create(dt_htab_ops_t *ops) { - dt_htab_t *htab = dt_alloc(dtp, sizeof(dt_htab_t)); + dt_htab_t *htab = malloc(sizeof(dt_htab_t)); if (!htab) return NULL; @@ -79,9 +78,9 @@ dt_htab_t *dt_htab_create(dtrace_hdl_t *dtp, dt_htab_ops_t *ops) htab->nentries = 0; htab->ops = ops; - htab->tab = dt_calloc(dtp, htab->size, sizeof(dt_hbucket_t *)); + htab->tab = calloc(htab->size, sizeof(dt_hbucket_t *)); if (!htab->tab) { - dt_free(dtp, htab); + free(htab); return NULL; } @@ -91,7 +90,7 @@ dt_htab_t *dt_htab_create(dtrace_hdl_t *dtp, dt_htab_ops_t *ops) /* * Destroy a hashtable, deleting all its entries first. */ -void dt_htab_destroy(dtrace_hdl_t *dtp, dt_htab_t *htab) +void dt_htab_destroy(dt_htab_t *htab) { size_t i; @@ -112,8 +111,8 @@ void dt_htab_destroy(dtrace_hdl_t *dtp, dt_htab_t *htab) }; } - dt_free(dtp, htab->tab); - dt_free(dtp, htab); + free(htab->tab); + free(htab); } /* diff --git a/libdtrace/dt_htab.h b/libcommon/dt_htab.h similarity index 91% rename from libdtrace/dt_htab.h rename to libcommon/dt_htab.h index d39ae65e..906c91fd 100644 --- a/libdtrace/dt_htab.h +++ b/libcommon/dt_htab.h @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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. */ @@ -12,8 +12,6 @@ extern "C" { #endif -struct dtrace_hdl; - typedef uint32_t (*htab_hval_fn)(const void *); typedef int (*htab_cmp_fn)(const void *, const void *); typedef void *(*htab_add_fn)(void *, void *); @@ -93,8 +91,8 @@ typedef struct dt_hentry { typedef struct dt_htab dt_htab_t; typedef struct dt_htab_next dt_htab_next_t; -extern dt_htab_t *dt_htab_create(struct dtrace_hdl *dtp, dt_htab_ops_t *ops); -extern void dt_htab_destroy(struct dtrace_hdl *dtp, dt_htab_t *htab); +extern dt_htab_t *dt_htab_create(dt_htab_ops_t *ops); +extern void dt_htab_destroy(dt_htab_t *htab); extern int dt_htab_insert(dt_htab_t *htab, void *entry); extern void *dt_htab_lookup(const dt_htab_t *htab, const void *entry); typedef int dt_htab_ecmp_fn(const void *entry, void *arg); diff --git a/libdtrace/Build b/libdtrace/Build index 7e6e8a38..219ff9b3 100644 --- a/libdtrace/Build +++ b/libdtrace/Build @@ -28,7 +28,6 @@ libdtrace-build_SOURCES = dt_aggregate.c \ dt_errtags.c \ dt_grammar.c \ dt_handle.c \ - dt_htab.c \ dt_ident.c \ dt_lex.c \ dt_link.c \ diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c index 9088a90d..b0bf73d1 100644 --- a/libdtrace/dt_consume.c +++ b/libdtrace/dt_consume.c @@ -3011,7 +3011,7 @@ dt_consume_proc_exits(dtrace_hdl_t *dtp) int dt_consume_init(dtrace_hdl_t *dtp) { - dtp->dt_spec_bufs = dt_htab_create(dtp, &dt_spec_buf_htab_ops); + dtp->dt_spec_bufs = dt_htab_create(&dt_spec_buf_htab_ops); if (!dtp->dt_spec_bufs) return dt_set_errno(dtp, EDT_NOMEM); @@ -3028,7 +3028,7 @@ dt_consume_fini(dtrace_hdl_t *dtp) dt_free(dtp, dtsd); } - dt_htab_destroy(dtp, dtp->dt_spec_bufs); + dt_htab_destroy(dtp->dt_spec_bufs); } dtrace_workstatus_t diff --git a/libdtrace/dt_kernel_module.c b/libdtrace/dt_kernel_module.c index e21ecc51..baeabeab 100644 --- a/libdtrace/dt_kernel_module.c +++ b/libdtrace/dt_kernel_module.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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. */ @@ -75,7 +75,7 @@ dt_kern_path_create(dtrace_hdl_t *dtp, char *name, char *path) dt_kern_path_t tmpl; if (!dtp->dt_kernpaths) { - dtp->dt_kernpaths = dt_htab_create(dtp, &kernpath_htab_ops); + dtp->dt_kernpaths = dt_htab_create(&kernpath_htab_ops); if (!dtp->dt_kernpaths) return NULL; /* caller must handle allocation failure */ diff --git a/libdtrace/dt_module.c b/libdtrace/dt_module.c index d45947d7..b3c8e247 100644 --- a/libdtrace/dt_module.c +++ b/libdtrace/dt_module.c @@ -138,7 +138,7 @@ dt_module_create(dtrace_hdl_t *dtp, const char *name) dt_module_t *dmp; if (!dtp->dt_mods) { - dtp->dt_mods = dt_htab_create(dtp, &dt_module_htab_ops); + dtp->dt_mods = dt_htab_create(&dt_module_htab_ops); if (!dtp->dt_mods) return NULL; } diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c index 0bda3504..01c36a76 100644 --- a/libdtrace/dt_open.c +++ b/libdtrace/dt_open.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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. */ @@ -1270,10 +1270,10 @@ dtrace_close(dtrace_hdl_t *dtp) dt_idhash_destroy(dtp->dt_bpfsyms); - dt_htab_destroy(dtp, dtp->dt_kernsyms); + dt_htab_destroy(dtp->dt_kernsyms); dtp->dt_kernsyms = NULL; - dt_htab_destroy(dtp, dtp->dt_mods); - dt_htab_destroy(dtp, dtp->dt_kernpaths); + dt_htab_destroy(dtp->dt_mods); + dt_htab_destroy(dtp->dt_kernpaths); if (dtp->dt_shared_btf != NULL) dt_btf_destroy(dtp, dtp->dt_shared_btf); @@ -1303,7 +1303,7 @@ dtrace_close(dtrace_hdl_t *dtp) dt_dof_fini(dtp); dt_probe_fini(dtp); - dt_htab_destroy(dtp, dtp->dt_provs); + dt_htab_destroy(dtp->dt_provs); for (i = 1; i < dtp->dt_cpp_argc; i++) free(dtp->dt_cpp_argv[i]); diff --git a/libdtrace/dt_probe.c b/libdtrace/dt_probe.c index ccaa3081..28a1133f 100644 --- a/libdtrace/dt_probe.c +++ b/libdtrace/dt_probe.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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. */ @@ -1278,11 +1278,11 @@ dt_probe_dependent_iter(dtrace_hdl_t *dtp, const dt_probe_t *prp, void dt_probe_init(dtrace_hdl_t *dtp) { - dtp->dt_byprv = dt_htab_create(dtp, &prv_htab_ops); - dtp->dt_bymod = dt_htab_create(dtp, &mod_htab_ops); - dtp->dt_byfun = dt_htab_create(dtp, &fun_htab_ops); - dtp->dt_byprb = dt_htab_create(dtp, &prb_htab_ops); - dtp->dt_byfqn = dt_htab_create(dtp, &fqn_htab_ops); + dtp->dt_byprv = dt_htab_create(&prv_htab_ops); + dtp->dt_bymod = dt_htab_create(&mod_htab_ops); + dtp->dt_byfun = dt_htab_create(&fun_htab_ops); + dtp->dt_byprb = dt_htab_create(&prb_htab_ops); + dtp->dt_byfqn = dt_htab_create(&fqn_htab_ops); dtp->dt_probes = NULL; dtp->dt_probes_sz = 0; @@ -1315,11 +1315,11 @@ dt_probe_fini(dtrace_hdl_t *dtp) dt_probe_destroy(prp); } - dt_htab_destroy(dtp, dtp->dt_byprv); - dt_htab_destroy(dtp, dtp->dt_bymod); - dt_htab_destroy(dtp, dtp->dt_byfun); - dt_htab_destroy(dtp, dtp->dt_byprb); - dt_htab_destroy(dtp, dtp->dt_byfqn); + dt_htab_destroy(dtp->dt_byprv); + dt_htab_destroy(dtp->dt_bymod); + dt_htab_destroy(dtp->dt_byfun); + dt_htab_destroy(dtp->dt_byprb); + dt_htab_destroy(dtp->dt_byfqn); dtp->dt_byprv = NULL; dtp->dt_bymod = NULL; dtp->dt_byfun = NULL; diff --git a/libdtrace/dt_provider.c b/libdtrace/dt_provider.c index 06f0b039..0c459aba 100644 --- a/libdtrace/dt_provider.c +++ b/libdtrace/dt_provider.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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. */ @@ -90,7 +90,7 @@ static dt_provider_t * dt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp) { if (!dtp->dt_provs) { - dtp->dt_provs = dt_htab_create(dtp, &dt_provider_htab_ops); + dtp->dt_provs = dt_htab_create(&dt_provider_htab_ops); if (dtp->dt_provs == NULL) return NULL; } diff --git a/libdtrace/dt_symtab.c b/libdtrace/dt_symtab.c index 3819c21d..62c458f3 100644 --- a/libdtrace/dt_symtab.c +++ b/libdtrace/dt_symtab.c @@ -167,7 +167,7 @@ dt_symtab_create(dtrace_hdl_t *dtp) dt_symtab_t *symtab; if (!dtp->dt_kernsyms) { - dtp->dt_kernsyms = dt_htab_create(dtp, &dt_symtab_htab_ops); + dtp->dt_kernsyms = dt_htab_create(&dt_symtab_htab_ops); if (!dtp->dt_kernsyms) return NULL; -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:02 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:02 -0400 Subject: [DTrace-devel] [PATCH 10/17] htab: move str2hval() to dt_htab Message-ID: Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock --- libcommon/dt_htab.c | 28 ++++++++++++++++++++++++++++ libcommon/dt_htab.h | 2 ++ libdtrace/dt_string.c | 30 +----------------------------- libdtrace/dt_string.h | 3 +-- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/libcommon/dt_htab.c b/libcommon/dt_htab.c index 43782202..ee119031 100644 --- a/libcommon/dt_htab.c +++ b/libcommon/dt_htab.c @@ -62,6 +62,34 @@ struct dt_htab_next { int exhausted; }; +/* + * Calculate a hash value based on a given string and an initial value. The + * initial value is used to calculate compound hash values, e.g. + * + * uint32_t hval; + * + * hval = str2hval(str1, 0); + * hval = str2hval(str2, hval); + */ +uint32_t str2hval(const char *p, uint32_t hval) +{ + uint32_t g; + + if (!p) + return hval; + + while (*p) { + hval = (hval << 4) + *p++; + g = hval & 0xf0000000; + if (g != 0) { + hval ^= (g >> 24); + hval ^= g; + } + } + + return hval; +} + /* * Create a new (empty) hashtable. */ diff --git a/libcommon/dt_htab.h b/libcommon/dt_htab.h index 906c91fd..13de552a 100644 --- a/libcommon/dt_htab.h +++ b/libcommon/dt_htab.h @@ -91,6 +91,8 @@ typedef struct dt_hentry { typedef struct dt_htab dt_htab_t; typedef struct dt_htab_next dt_htab_next_t; +extern uint32_t str2hval(const char *p, uint32_t hval); + extern dt_htab_t *dt_htab_create(dt_htab_ops_t *ops); extern void dt_htab_destroy(dt_htab_t *htab); extern int dt_htab_insert(dt_htab_t *htab, void *entry); diff --git a/libdtrace/dt_string.c b/libdtrace/dt_string.c index c3096947..414f1bb8 100644 --- a/libdtrace/dt_string.c +++ b/libdtrace/dt_string.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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. */ @@ -13,34 +13,6 @@ #include -/* - * Calculate a hash value based on a given string and an initial value. The - * initial value is used to calculate compound hash values, e.g. - * - * uint32_t hval; - * - * hval = str2hval(str1, 0); - * hval = str2hval(str2, hval); - */ -uint32_t str2hval(const char *p, uint32_t hval) -{ - uint32_t g; - - if (!p) - return hval; - - while (*p) { - hval = (hval << 4) + *p++; - g = hval & 0xf0000000; - if (g != 0) { - hval ^= (g >> 24); - hval ^= g; - } - } - - return hval; -} - /* * Transform string s inline, converting each embedded C escape sequence string * to the corresponding character. For example, the substring "\n" is replaced diff --git a/libdtrace/dt_string.h b/libdtrace/dt_string.h index e04e2ab5..854c0fb7 100644 --- a/libdtrace/dt_string.h +++ b/libdtrace/dt_string.h @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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. */ @@ -16,7 +16,6 @@ extern "C" { #endif -extern uint32_t str2hval(const char *, uint32_t); extern size_t stresc2chr(char *); extern char *strchr2esc(const char *, size_t); extern const char *strbasename(const char *); -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:03 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:03 -0400 Subject: [DTrace-devel] [PATCH 11/17] dtprobed: make sure that retry one time means exactly that Message-ID: Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock --- dtprobed/dtprobed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtprobed/dtprobed.c b/dtprobed/dtprobed.c index de15e546..b5c015ac 100644 --- a/dtprobed/dtprobed.c +++ b/dtprobed/dtprobed.c @@ -771,7 +771,7 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, errmsg = "parsed DOF read failed"; provider = usdt_read(pid, in); if (!provider) { - if (tries++ > 1) + if (tries++ > 0) goto err; /* * Tidying reopens the parser in and out pipes: catch -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:04 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:04 -0400 Subject: [DTrace-devel] [PATCH 12/17] usdt: add HASUSDT to the helper ioctl interface Message-ID: Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh --- include/dtrace/ioctl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/dtrace/ioctl.h b/include/dtrace/ioctl.h index 2273453a..9ecdc385 100644 --- a/include/dtrace/ioctl.h +++ b/include/dtrace/ioctl.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. */ #ifndef _DTRACE_IOCTL_H_ @@ -15,5 +15,6 @@ #define DTRACEHIOC_ADD _IOW(DTRACEHIOC, 1, dof_hdr_t) #define DTRACEHIOC_REMOVE _IOW(DTRACEHIOC, 2, int) #define DTRACEHIOC_ADDDOF _IOW(DTRACEHIOC, 3, dof_helper_t) +#define DTRACEHIOC_HASUSDT _IOW(DTRACEHIOC, 4, void *) #endif /* _DTRACE_IOCTL_H */ -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:04 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:04 -0400 Subject: [DTrace-devel] [PATCH 13/17] dtprobed, usdt parser: add support for ELF notes-based USDT Message-ID: Signed-off-by: Kris Van Hees --- dtprobed/dof_stash.c | 456 ++++++++++++++----- dtprobed/dof_stash.h | 4 +- dtprobed/dtprobed.c | 183 +++++++- libcommon/Build | 3 +- libcommon/usdt_parser.c | 17 +- libcommon/usdt_parser.h | 21 +- libcommon/usdt_parser_dof.c | 1 + libcommon/usdt_parser_host.c | 7 +- libcommon/usdt_parser_notes.c | 774 ++++++++++++++++++++++++++++++++ uts/common/sys/usdt_note_defs.h | 18 + 10 files changed, 1364 insertions(+), 120 deletions(-) create mode 100644 libcommon/usdt_parser_notes.c create mode 100644 uts/common/sys/usdt_note_defs.h diff --git a/dtprobed/dof_stash.c b/dtprobed/dof_stash.c index 6a4ecb86..6f176f2e 100644 --- a/dtprobed/dof_stash.c +++ b/dtprobed/dof_stash.c @@ -14,8 +14,12 @@ * * /run/dtrace/stash/: Things private to dtprobed. * - * .../dof/$dev-$ino: DOF contributed by particular mappings, in raw form - * (as received from some probe-containing program). + * .../dof/$dev-$ino: USDT definition data contributed by particular + * mappings, in raw form (as received from some probe-containing program). + * + * .../dof/$dev-$ino-$n: Additional USDT definition data contributed by + * particular mappings, in raw form (as received from some probe-containing + * program). * * .../dof-pid/$pid/$dev-$ino/: contains everything relating to DOF * contributed by a particular USDT-containing ELF object within a given @@ -34,12 +38,14 @@ * $dev-$ino (as in the $dev-$ino directory entries): the dev/ino of the * process's primary text mapping, as given by libproc. * - * .../dof-pid/$pid/$dev-$ino/raw: hardlink to the DOF for a given DOF - * source. Pruned of dead processes at startup and on occasion: entries also - * deleted on receipt of DTRACEHIOC_REMOVE ioctls. A hardlink is used in - * order to bump the link count for the corresponding DOF in the dof/ - * directory: when this link count falls to 1, the DOF is considered dead and - * the corresponding probe is removed. + * .../dof-pid/$pid/$dev-$ino/raw and + * .../dof-pid/$pid/$dev-$ino/raw-$n: hardlinks to the USDT definition data + * for a given probe-containing program. Pruned of dead processes at + * startup and on occasion: entries also deleted on receipt of + * DTRACEHIOC_REMOVE ioctls. A hardlink is used in order to bump the link + * count for the corresponding data in the dof/ directory: when this link + * count falls to 1, the data is considered dead and the corresponding probe + * is removed. * * .../dof-pid/$pid/$dev-$ino/dh: Raw form of the dof_helper_t received from * a given DTRACEHIOC_ADDDOF, serialized straight to disk with no changes. @@ -394,58 +400,163 @@ write_chunk(int fd, const void *buf, size_t size) } /* - * Write out a piece of raw DOF. Returns the length of the file written, - * or 0 if none was needed (or -1 on error). + * Prototype for utility function for usdt_data_apply(). Arguments are: + * - Directory fd + * - Base filename + * - USDT data + * - 'all' flag + * - Secondary directory fd + */ +typedef int (*usdt_data_fn)(int, const char *, const usdt_data_t *, int, int); + +/* + * Call the given function for every data block in the USDT data. Each call + * will be provided with the appropriate adjusted filename. + * + * If all == 0, returns the number of calls that returned true. + * If all == 1, returns 0 if any of the calls did not return true, and + * otherwise the total number of calls (that all returned true). + * Return -1 if the operation fails. */ static int -dof_stash_write_raw(int dirfd, const char *name, const void *buf, size_t size) +usdt_data_apply(usdt_data_fn func, int dirfd, const char *name, + const usdt_data_t *data, int all, int dirfd2) { - struct stat s; - int fd; - - /* - * Sanity check: if the DOF already exists but is not the same size as - * the DOF we already have, complain, and replace it. If it does exist, - * there's no need to write it out. - * - * If we can't even unlink it or write it out, we give up -- the stash - * has failed and we won't be able to do anything it implies. - * - * (This is only a crude check -- obviously distinct raw DOF could be - * the same size by pure chance.) - */ - if (fstatat(dirfd, name, &s, 0) == 0) { - if (s.st_size == size) - return 0; + int i, cnt; + char *fn = (char *)name; + + for (i = cnt = 0; data != NULL; i++, data = data->next) { + if (i > 0) { + if (asprintf(&fn, "%s-%d", name, i) < 0) { + fuse_log(FUSE_LOG_ERR, "dtprobed: out of memory making part name\n"); + return -1; + } + } - fuse_log(FUSE_LOG_ERR, "dtprobed: DOF %s already exists, " - "but is %zx bytes long, not %zx: replacing\n", - name, s.st_size, size); - if (unlinkat(dirfd, name, 0) < 0) { - fuse_log(FUSE_LOG_ERR, "dtprobed: cannot remove old DOF %s: %s\n", - name, strerror(errno)); + switch (func(dirfd, fn, data, i, dirfd2)) { + case 1: + cnt++; + break; + case 0: + break; + case -1: return -1; } + + if (i > 0) + free(fn); } - if ((fd = openat(dirfd, name, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) { - fuse_log(FUSE_LOG_ERR, "dtprobed: cannot write out raw DOF: %s\n", - strerror(errno)); - return -1; + if (all) + return cnt == i ? 1 : 0; + + return cnt; +} + +/* + * Utility function used through usdt_data_apply(). This returns 1 if the file + * is considered identical to the data block; otherwise 0. + * + * Note: if USDT data exists and has the same size, it is deemed identical. + * (This is only a crude check -- distinct raw USDT data could be the same size + * by pure chance.) + */ +static int +stale_data_file(int dirfd, const char *fn, const usdt_data_t *data, int idx, + int dummy) +{ + struct stat s; + + if (fstatat(dirfd, fn, &s, 0) == 0) + return s.st_size == data->size ? 1 : 0; + + return 0; +} + +/* + * Utility function used through usdt_data_apply(). Writes a USDT data block + * as raw data to disk. Returns 1 on success; -1 on failure. + */ +static int +write_raw_data(int dirfd, const char *fn, const usdt_data_t *data, int idx, + int dummy) +{ + int fd; + + if ((fd = openat(dirfd, fn, O_CREAT | O_TRUNC | O_WRONLY, 0644)) < 0) { + fuse_log(FUSE_LOG_ERR, + "dtprobed: cannot open raw data %s: %s\n", + fn, strerror(errno)); + return 0; + } + if (write_chunk(fd, &data->base, sizeof(size_t)) < 0 || + write_chunk(fd, data->buf, data->size) < 0) { + fuse_log(FUSE_LOG_ERR, + "dtprobed: cannot write out raw data %s: %s\n", + fn, strerror(errno)); + close(fd); + return 0; + } + if (close(fd) < 0) { + fuse_log(FUSE_LOG_ERR, + "dtprobed: cannot close raw data %s: %s\n", + fn, strerror(errno)); + return 0; } - if (write_chunk(fd, buf, size) < 0) - goto err; + return 1; +} - if (close(fd) < 0) - goto err; - return size + sizeof(uint64_t); +/* + * Utility function used through usdt_data_apply(). Removes the given file, + * and returns 1 (failures can be ignored - nothing we can do about them). + */ +static int +remove_data_file(int dirfd, const char *fn, const usdt_data_t *data, int idx, + int dummy) +{ + unlinkat(dirfd, fn, 0); -err: - fuse_log(FUSE_LOG_ERR, "dtprobed: cannot write out DOF: %s\n", - strerror(errno)); - unlinkat(dirfd, name, 0); - close(fd); + return 1; +} + +/* + * Write out a piece of raw USDT definition data. Returns a positive integer + * (the number of files written) if data was written, or 0 if none was needed + * (or -1 on error). + */ +static int +dof_stash_write_raw(int dirfd, const char *name, const usdt_data_t *data) +{ + int rc; + + /* + * Verify whether the raw USDT data already exists on disk. The return + * value will be 1 if it exists and all blocks are deemed identical to + * the USDT data; otherwise 0. (Errors result in returning -1.) + */ + rc = usdt_data_apply(stale_data_file, dirfd, name, data, 1, 0); + if (rc == -1) + return -1; + + if (rc == 1) + return 0; + + /* + * Write out the USDT data blocks. + * + * rc = 1: All blocks written successfully. + * rc = 0: Some blocks not written. + * rc = -1: An erorr happened (some blocks not written). + * + * If some blocks were not written, we try to clean up (remove all that + * was written), and return -1. + */ + rc = usdt_data_apply(write_raw_data, dirfd, name, data, 1, 0); + if (rc != 0) + return rc; + + usdt_data_apply(remove_data_file, dirfd, name, data, 0, 0); return -1; } @@ -887,6 +998,33 @@ err: return 0; } +/* + * Utility function used through usdt_data_apply(). Create a link to the given + * file as raw-%n and return 1; return 0 on failure. + */ +static int +create_raw_link(int dirfd, const char *fn, const usdt_data_t *data, int idx, + int rdirfd) +{ + char *rn = "raw"; + int rc; + + if (idx > 0) { + if (asprintf(&rn, "raw-%d", idx) < 0) { + fuse_log(FUSE_LOG_ERR, + "dtprobed: out of memory making part name\n"); + return -1; + } + } + + rc = linkat(dirfd, fn, rdirfd, rn, 0); + + if (idx > 0) + free(rn); + + return rc < 0 ? 0 : 1; +} + /* * Add a piece of raw DOF from a given (pid, dev, ino) triplet. May remove * stale DOF in the process. @@ -895,7 +1033,7 @@ err: */ int dof_stash_add(pid_t pid, dev_t dev, ino_t ino, dev_t exec_dev, dev_t exec_ino, - const dof_helper_t *dh, const void *dof, size_t size) + const dof_helper_t *dh, const usdt_data_t *data) { char *dof_name = make_dof_name(dev, ino); char *pid_name = make_numeric_name(pid); @@ -974,12 +1112,13 @@ dof_stash_add(pid_t pid, dev_t dev, ino_t ino, dev_t exec_dev, dev_t exec_ino, * otherwise. */ new_dof = 1; - switch (dof_stash_write_raw(dof_dir, dof_name, dof, size)) { + switch (dof_stash_write_raw(dof_dir, dof_name, data)) { case 0: new_dof = 0; break; case -1: goto err_unlink_nomsg; break; } - if (linkat(dof_dir, dof_name, perpid_dof_dir, "raw", 0) < 0) + if (usdt_data_apply(create_raw_link, dof_dir, dof_name, data, 1, + perpid_dof_dir) == 0) goto err_unlink_msg; if (dof_stash_write_file(perpid_dof_dir, "dh", dh, @@ -1041,7 +1180,7 @@ err_unlink_msg: "DOF mapping %lx/%lx into place: %s\n", pid, dev, ino, strerror(errno)); err_unlink_nomsg: - unlinkat(perpid_dof_dir, "raw", 0); + usdt_data_apply(remove_data_file, perpid_dof_dir, "raw", data, 0, 0); unlinkat(perpid_dir, dof_name, AT_REMOVEDIR); if (gen_name) @@ -1052,8 +1191,10 @@ err_unlink_nomsg: unlinkat(pid_dir, pid_name, AT_REMOVEDIR); } - if (new_dof) + if (new_dof) { + usdt_data_apply(remove_data_file, dof_dir, dof_name, data, 0, 0); unlinkat(dof_dir, dof_name, 0); + } goto out_free; } @@ -1132,44 +1273,64 @@ unlinkat_many(int dirfd, const char **names) } /* - * Determine if a file or directory (in the DOF stash) should be deleted. + * Utility function used through usdt_data_apply(). Determine if a file in the + * stash should be deleted, and if so, do it. Returns 1 if it got deleted; + * returns 0 if not needed; returns -1 on error. */ static int -refcount_cleanup_p(int dirfd, const char *name, int isdir) +refcount_cleanup_file(int dirfd, const char *fn, const usdt_data_t *data, + int idx, int dummy) { struct stat s; - if (fstatat(dirfd, name, &s, 0) != 0) { + if (fstatat(dirfd, fn, &s, 0) != 0) { + if (errno == ENOENT) { + ((usdt_data_t *)data)->next = NULL; + return 1; + } + fuse_log(FUSE_LOG_ERR, "Cannot stat %s for cleanup: %s\n", - name, strerror(errno)); + fn, strerror(errno)); return -1; } - if ((isdir && s.st_nlink != 2) || (!isdir && s.st_nlink != 1)) + if (s.st_nlink != 1) return 0; + if (unlinkat(dirfd, fn, 0) < 0) { + fuse_log(FUSE_LOG_ERR, + "dtprobed: cannot remove old data %s: %s\n", + fn, strerror(errno)); + return -1; + } + return 1; } - /* - * Delete a file or directory (in the DOF stash) if it has no other links. + * Delete a directory (in the stash) if it has no other links. */ static int -refcount_cleanup(int dirfd, const char *name, int isdir) +refcount_cleanup_dir(int dirfd, const char *name) { - switch (refcount_cleanup_p(dirfd, name, isdir)) { - case -1: return -1; - case 0: return 0; - default: break; + struct stat s; + + if (fstatat(dirfd, name, &s, 0) != 0) { + fuse_log(FUSE_LOG_ERR, "Cannot stat %s for cleanup: %s\n", + name, strerror(errno)); + return -1; } - if (unlinkat(dirfd, name, isdir ? AT_REMOVEDIR : 0) < 0) { + if (s.st_nlink != 2) + return 0; + + if (unlinkat(dirfd, name, AT_REMOVEDIR) < 0) { fuse_log(FUSE_LOG_ERR, "dtprobed: cannot remove old DOF %s: %s\n", name, strerror(errno)); return -1; } - return 0; + + return 1; } /* @@ -1262,6 +1423,27 @@ err: return -1; } +/* + * Utility function used through usdt_data_apply(). Removes the given file, + * and returns 1 (failures can be ignored - nothing we can do about them). + * If a file was successfully removed, data->next to set to data to signal the + * iterator to move on to the next file. If no file was found, data->next is + * set to NULL to indicate that we are done. + */ +static int +remove_raw_file(int dirfd, const char *fn, const usdt_data_t *data, int idx, + int dummy) +{ + usdt_data_t *dp = (usdt_data_t *)data; + + if (unlinkat(dirfd, fn, 0) < 0 && errno == ENOENT) + dp->next = NULL; + else + dp->next = dp; + + return 1; +} + /* * Remove a piece of DOF, identified by generation counter. Return -1 on error. * @@ -1279,6 +1461,7 @@ dof_stash_remove(pid_t pid, int gen) struct stat gen_stat; int err = -1; const char *unlink_err = NULL; + usdt_data_t data; /* * Figure out the per-PID DOF directory by following the gen-counter @@ -1333,10 +1516,14 @@ dof_stash_remove(pid_t pid, int gen) fuse_log(FUSE_LOG_DEBUG, "%i: gen_name: %s; gen_linkname: %s; perpid_dof_dir: %i\n", pid, gen_name, gen_linkname, perpid_dof_dir); - if (unlinkat(perpid_dof_dir, "raw", 0) != 0 && errno != ENOENT) { - fuse_log(FUSE_LOG_ERR, "dtprobed: cannot unlink per-PID raw DOF for PID %i generation %i: %s\n", - pid, gen, strerror(errno)); - } + /* + * We use a fake USDT data structure so we can use the USDT data block + * iterator to call our calllback. It will keep iterating until the + * first non-existant file is encountered (indicating we reached the + * endof the data blocks). + */ + data.next = &data; + usdt_data_apply(remove_raw_file, perpid_dof_dir, "raw", &data, 0, 0); if (dof_stash_remove_parsed(pid, perpid_dof_dir, gen_linkname) < 0) unlink_err = "parsed probes dir entries"; @@ -1353,7 +1540,15 @@ dof_stash_remove(pid_t pid, int gen) if (unlinkat(perpid_dir, gen_name, 0) < 0) unlink_err = gen_name; - if (refcount_cleanup(dof_dir, gen_linkname, 0) < 0) + /* + * We use a fake USDT data structure so we can use the USDT data block + * iterator to call our calllback. It will keep iterating until the + * first non-existance file is encountered (indicating we reached the + * endof the data blocks). + */ + data.next = &data; + if (usdt_data_apply(refcount_cleanup_file, dof_dir, gen_linkname, + &data, 0, 0) < 0) unlink_err = gen_linkname; /* @@ -1380,7 +1575,7 @@ dof_stash_remove(pid_t pid, int gen) pid, strerror(errno)); goto err; } - refcount_cleanup(pid_dir, pid_name, 1); + refcount_cleanup_dir(pid_dir, pid_name); } if (unlink_err) @@ -1556,6 +1751,62 @@ scan_failure: goto out; } +/* + * Utility function used through usdt_data_apply(). Read a USDT data block + * from disk. Returns 1 on success of if the file is not found; -1 on error. + */ +static int +read_raw_data(int dirfd, const char *fn, const usdt_data_t *data, int idx, + int dummy) +{ + int fd; + usdt_data_t *dp; + + /* + * If the file does not exist, we assume that we have reached the last + * file for this USDT data. We can return 1, because we know that + * data->next is NULL so the iterator will stop. + */ + if ((fd = openat(dirfd, fn, O_RDONLY | O_CLOEXEC)) < 0) { + if (errno == ENOENT) + return 1; + + return -1; + } + + /* + * Allocate a new block. We set the next pointer to the block itself + * so that the iterator that called us knows that we need look for a + * following block. If none is found, the next call will assign NULL + * to this next pointer and end the block chain. + */ + if ((dp = malloc(sizeof(usdt_data_t))) == NULL) + return -1; + + dp->size = 0; + dp->base = 0; + dp->next = NULL; + + if ((dp->buf = read_file(fd, -1, &dp->size)) == NULL) { + close(fd); + free(dp); + return -1; + } + + /* + * Raw data blocks are written as a base address (size_t) followed by + * the actual data. Set dp->base from the data just read, and adjust + * the buffer pointer and size. When the buffer is to be freed, the + * pointer will need to be adjusted back. + */ + dp->base = *(size_t *)dp->buf; + dp->size -= sizeof(size_t); + dp->buf = ((char *)dp->buf) + sizeof(size_t); + + ((usdt_data_t *)data)->next = dp; + return 1; +} + /* * Reparse all DOF. Mappings that cannot be reparsed are simply ignored, on the * grounds that most DOF, most of the time, is not used, so this will likely be @@ -1639,10 +1890,9 @@ reparse_dof(int out, int in, int fd; dev_t dev; ino_t ino; - size_t dof_size, dh_size; - void *dof = NULL; + size_t dh_size; void *dh = NULL; - usdt_data_t data; + usdt_data_t data, *dp, *nxt; if (errno != 0) { fuse_log(FUSE_LOG_ERR, "reparsing DOF: cannot read per-PID DOF mappings for pid %s: %s\n", @@ -1707,53 +1957,53 @@ reparse_dof(int out, int in, continue; } - if ((fd = openat(mapping_fd, "raw", O_RDONLY | O_CLOEXEC)) < 0) { - fuse_log(FUSE_LOG_ERR, "when reparsing DOF, cannot open raw DOF for PID %s, mapping %s: ignored: %s\n", + data.base = 0; + data.size = 0; + data.buf = NULL; + data.next = NULL; + if (usdt_data_apply(read_raw_data, mapping_fd, "raw", + &data, 0, 0) <= 0) { + fuse_log(FUSE_LOG_ERR, + "reparse: cannot open raw data for PID %s, mapping %s: ignored: %s\n", pid_ent->d_name, mapping_ent->d_name, strerror(errno)); - close(mapping_fd); - continue; + goto read_err; } - if ((dof = read_file(fd, -1, &dof_size)) == NULL) { - fuse_log(FUSE_LOG_ERR, "when reparsing DOF, cannot read raw DOF for PID %s, mapping %s: ignored: %s\n", - pid_ent->d_name, mapping_ent->d_name, strerror(errno)); - close(mapping_fd); - close(fd); - continue; - } - close(fd); - if ((fd = openat(mapping_fd, "dh", O_RDONLY | O_CLOEXEC)) < 0) { fuse_log(FUSE_LOG_ERR, "when reparsing DOF, cannot open dh for PID %s, mapping %s: ignored: %s\n", pid_ent->d_name, mapping_ent->d_name, strerror(errno)); - free(dof); - close(mapping_fd); - continue; + goto read_err; } if ((dh = read_file(fd, -1, &dh_size)) == NULL) { fuse_log(FUSE_LOG_ERR, "when reparsing DOF, cannot read dh for PID %s, mapping %s: ignored: %s\n", pid_ent->d_name, mapping_ent->d_name, strerror(errno)); - free(dof); - close(mapping_fd); close(fd); - continue; + goto read_err; } close(fd); - fuse_log(FUSE_LOG_DEBUG, "Reparsing DOF for PID %s, mapping %s\n", + fuse_log(FUSE_LOG_DEBUG, + "Reparsing raw data for PID %s, mapping %s\n", pid_ent->d_name, mapping_ent->d_name); - data.buf = dof; - data.size = dof_size; - data.next = NULL; - if (reparse(pid, out, in, dev, ino, 0, 0, dh, &data, 1) < 0) - fuse_log(FUSE_LOG_ERR, "when reparsing DOF, cannot parse DOF for PID %s, mapping %s: ignored\n", - pid_ent->d_name, mapping_ent->d_name); - free(dof); + if (reparse(pid, out, in, dev, ino, 0, 0, + dh, data.next, 1) < 0) + fuse_log(FUSE_LOG_ERR, + "reparse: cannot parse raw data for PID %s, mapping %s: ignored\n", + pid_ent->d_name, mapping_ent->d_name); + free(dh); + +read_err: close(mapping_fd); + for (dp = data.next; dp != NULL; dp = nxt) { + nxt = dp->next; + free(((char *)dp->buf) - sizeof(size_t)); + free(dp); + } + continue; perpid_err: diff --git a/dtprobed/dof_stash.h b/dtprobed/dof_stash.h index 1017d2d2..32b5eb52 100644 --- a/dtprobed/dof_stash.h +++ b/dtprobed/dof_stash.h @@ -26,8 +26,8 @@ int dof_stash_write_parsed(pid_t pid, dev_t dev, ino_t ino, dt_list_t *accum); void dof_stash_free(dt_list_t *accum); int dof_stash_add(pid_t pid, dev_t dev, ino_t ino, dev_t exec_dev, - dev_t exec_ino, const dof_helper_t *dh, const void *dof, - size_t size); + dev_t exec_ino, const dof_helper_t *dh, + const usdt_data_t *data); int dof_stash_remove(pid_t pid, int gen); int dof_stash_remove_pid(pid_t pid); diff --git a/dtprobed/dtprobed.c b/dtprobed/dtprobed.c index b5c015ac..a8085865 100644 --- a/dtprobed/dtprobed.c +++ b/dtprobed/dtprobed.c @@ -439,6 +439,174 @@ usdt_read(pid_t pid, int in) return reply; } +/* + * Retrieve and process USDT probe data from a .note.usdt section. + * The .rodata section is also needed because function names are stored there. + */ +static int +handle_usdt_notes(pid_t pid, uintptr_t addr) +{ + ps_prochandle *P = NULL; + const prmap_t *mapp, *exec_mapp; + const prmap_file_t *prf; + dof_helper_t dh; + const char *fn, *mod; + int fd = -1; + Elf *elf = NULL; + size_t shstrndx; + GElf_Shdr shdr; + size_t nbase, dbase; + Elf_Scn *scn = NULL, *nscn = NULL, *dscn = NULL;; + GElf_Ehdr ehdr; + Elf_Data *elfd, *elfn; + usdt_data_t ndata, ddata; + dev_t dev, exec_dev; + ino_t inum, exec_inum; + int gen = -1, err; + + /* Grab the process. */ + if ((P = Pgrab(pid, 2, 0, NULL, &err)) == NULL) { + fuse_log(FUSE_LOG_ERR, "%i: dtprobed: process grab failed: %s\n", + pid, strerror(err)); + return -1; + } + + /* Retrieve mapping information. */ + mapp = Paddr_to_map(P, addr); + if (mapp == NULL) { + fuse_log(FUSE_LOG_ERR, "%i: dtprobed: cannot look up mapping (process dead?)\n", + pid); + goto out; + } + + dev = mapp->pr_dev; + inum = mapp->pr_inum; + + prf = mapp->pr_file; + if (prf == NULL || (mapp = prf->first_segment) == NULL) { + fuse_log(FUSE_LOG_ERR, "%i: dtprobed: cannot look up mapping (process dead?)\n", + pid); + goto out; + } else if ((fn = prf->prf_mapname) == NULL) { + fuse_log(FUSE_LOG_ERR, "%i: dtprobed: cannot look up mapname (process dead?)\n", + pid); + goto out; + } + mod = strrchr(fn, '/'); + if (mod) + mod++; + else + mod = fn; + snprintf(dh.dofhp_mod, sizeof(dh.dofhp_mod), "%s", mod); + + dh.dofhp_addr = mapp->pr_vaddr; + dh.dofhp_dof = 0; + + fuse_log(FUSE_LOG_DEBUG, "%i: DOF helper { '%s', %lx, %lx }\n", + pid, dh.dofhp_mod, dh.dofhp_addr, dh.dofhp_dof); + + exec_mapp = Plmid_to_map(P, LM_ID_BASE, PR_OBJ_EXEC); + if (exec_mapp == NULL || (prf = exec_mapp->pr_file) == NULL) { + fuse_log(FUSE_LOG_ERR, "%i: dtprobed: cannot look up mapping (process dead?)\n", + pid); + goto out; + } + + exec_dev = exec_mapp->pr_dev; + exec_inum = exec_mapp->pr_inum; + + /* Open the mapping. */ + if ((fd = open(fn, O_RDONLY)) < 0) { + fuse_log(FUSE_LOG_ERR, "%i: dtprobed: cannot open %s: %s\n", + pid, fn, strerror(errno)); + goto out; + } + + Prelease(P, PS_RELEASE_NORMAL); + Pfree(P); + P = NULL; + + /* Retrieve the .note.usdt ELF section. */ + elf_version(EV_CURRENT); + if ((elf = elf_begin(fd, ELF_C_READ_MMAP, NULL)) == NULL || + elf_kind(elf) != ELF_K_ELF) + goto elf_err; + + elf_getshdrstrndx(elf, &shstrndx); + if (gelf_getehdr(elf, &ehdr) == NULL) + goto elf_err; + if (ehdr.e_type == ET_EXEC) + dh.dofhp_addr = 0; + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + const char *name; + + if (gelf_getshdr(scn, &shdr) == NULL) + goto elf_err; + + if (shdr.sh_type == SHT_NOTE && + (name = elf_strptr(elf, shstrndx, shdr.sh_name)) && + strcmp(name, ".note.usdt") == 0) { + nscn = scn; + nbase = shdr.sh_addr; + } else if (shdr.sh_type == SHT_PROGBITS && + (name = elf_strptr(elf, shstrndx, shdr.sh_name)) && + strcmp(name, ".rodata") == 0) { + dscn = scn; + dbase = shdr.sh_addr; + } + } + + if (nscn == NULL) { + fuse_log(FUSE_LOG_ERR, "%i: dtprobed: no %s section in %s\n", + pid, ".note.usdt", dh.dofhp_mod); + goto out; + } + if (dscn == NULL) { + fuse_log(FUSE_LOG_ERR, "%i: dtprobed: no %s section in %s\n", + pid, ".rodata", dh.dofhp_mod); + goto out; + } + + if ((elfn = elf_getdata(nscn, 0)) == NULL || + (elfd = elf_getdata(dscn, 0)) == NULL) + goto elf_err; + + fuse_log(FUSE_LOG_DEBUG, + "%i: %s with %s section (%lu bytes), %s section (%lu bytes)\n", + pid, dh.dofhp_mod, ".note.usdt", elfn->d_size, ".rodata", + elfd->d_size); + + ndata.base = nbase; + ndata.size = elfn->d_size; + ndata.buf = elfn->d_buf; + ndata.next = &ddata; + ddata.base = dbase; + ddata.size = elfd->d_size; + ddata.buf = elfd->d_buf; + ddata.next = NULL; + gen = process_dof(pid, parser_out_pipe, parser_in_pipe, dev, inum, + exec_dev, exec_inum, &dh, &ndata, 0); + + goto out; + +elf_err: + fuse_log(FUSE_LOG_ERR, "%i: dtprobed: cannot read ELF %s: %s\n", + pid, dh.dofhp_mod, elf_errmsg(elf_errno())); + +out: + if (elf) + elf_end(elf); + if (fd >= 0) + close(fd); + if (P) { + Prelease(P, PS_RELEASE_NORMAL); + Pfree(P); + } + + return gen; +} + /* * Get the (dev, inum) pair for the mapping the passed-in addr belongs to in the * given pid. (If there are multiple, it doesn't matter which we choose as long @@ -506,6 +674,13 @@ helper_ioctl(fuse_req_t req, int cmd, void *arg, */ switch (cmd) { + case DTRACEHIOC_HASUSDT: + fuse_log(FUSE_LOG_DEBUG, "DTRACEHIOC_HASUSDT from PID %i, addr %lx\n", + pid, (uintptr_t) arg); + if ((gen = handle_usdt_notes(pid, (uintptr_t) arg)) < 0) + goto process_err; + + goto process_done; case DTRACEHIOC_ADDDOF: break; case DTRACEHIOC_REMOVE: @@ -689,14 +864,16 @@ chunks_done: &exec_dev, &exec_inum)) < 0) goto process_err; - data.buf = (void *)buf; + data.base = 0; data.size = userdata->dof_hdr.dofh_loadsz; + data.buf = (void *)buf; data.next = NULL; if ((gen = process_dof(pid, parser_out_pipe, parser_in_pipe, dev, inum, exec_dev, exec_inum, &userdata->dh, &data, 0)) < 0) goto process_err; +process_done: if (fuse_reply_ioctl(req, gen, NULL, 0) < 0) goto process_err; @@ -846,8 +1023,8 @@ process_dof(pid_t pid, int out, int in, dev_t dev, ino_t inum, dev_t exec_dev, goto oom; if (!reparsing) - if ((gen = dof_stash_add(pid, dev, inum, exec_dev, exec_inum, dh, - data->buf, data->size)) < 0) + if ((gen = dof_stash_add(pid, dev, inum, exec_dev, exec_inum, + dh, data)) < 0) goto fileio; if (dof_stash_write_parsed(pid, dev, inum, &accum) < 0) { diff --git a/libcommon/Build b/libcommon/Build index 6237351f..c0f459fe 100644 --- a/libcommon/Build +++ b/libcommon/Build @@ -10,7 +10,8 @@ libcommon_TARGET = libcommon libcommon_DIR := $(current-dir) libcommon_CPPFLAGS := -Ilibcommon -Ilibproc -U_FORTIFY_SOURCE libcommon_SOURCES = dt_htab.c dt_list.c \ - usdt_parser.c usdt_parser_dof.c usdt_parser_host.c + usdt_parser.c usdt_parser_host.c \ + usdt_parser_dof.c usdt_parser_notes.c libcommon_NOCFLAGS := -D_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -D_FORTIFY_SOURCE=2 -D_FORTIFY_SOURCE=3 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=1 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=2 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 libcommon_NOCPPFLAGS := -D_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -D_FORTIFY_SOURCE=2 -D_FORTIFY_SOURCE=3 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=1 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=2 -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 libcommon_LIBSOURCES = libcommon diff --git a/libcommon/usdt_parser.c b/libcommon/usdt_parser.c index f301fd56..86419809 100644 --- a/libcommon/usdt_parser.c +++ b/libcommon/usdt_parser.c @@ -122,6 +122,10 @@ usdt_copyin_block(int in, int out, int *ok) memset(data, 0, sizeof(usdt_data_t)); + /* Get the offset of the data block. */ + if (!usdt_copyin(in, (char *)&data->base, sizeof(data->base))) + abort(); + /* Get the size of the data block. */ if (!usdt_copyin(in, (char *)&data->size, sizeof(data->size))) abort(); @@ -168,7 +172,7 @@ usdt_copyin_data(int in, int out, int *ok) if (!usdt_copyin(in, (char *)&cnt, sizeof(cnt))) abort(); - if (cnt >= usdt_maxcount) { + if (cnt > usdt_maxcount) { usdt_error(out, E2BIG, "block count %zi exceeds maximum %zi", cnt, usdt_maxcount); return NULL; @@ -207,9 +211,14 @@ usdt_destroy(dof_helper_t *dhp, usdt_data_t *data) void usdt_parse(int out, dof_helper_t *dhp, usdt_data_t *data) { - dof_parsed_t eof; - - if (usdt_parse_dof(out, dhp, data->buf) != 0) + dof_parsed_t eof; + int rc = -1; + + if (dhp->dofhp_dof) + rc = usdt_parse_dof(out, dhp, data->buf); + else + rc = usdt_parse_notes(out, dhp, data); + if (rc != 0) goto err; /* diff --git a/libcommon/usdt_parser.h b/libcommon/usdt_parser.h index 9dd97e28..d33370e4 100644 --- a/libcommon/usdt_parser.h +++ b/libcommon/usdt_parser.h @@ -20,9 +20,10 @@ */ typedef struct usdt_data usdt_data_t; struct usdt_data { - size_t size; - void *buf; - usdt_data_t *next; + size_t base; /* base address of section */ + size_t size; /* data size */ + void *buf; /* data content */ + usdt_data_t *next; /* next buffer */ }; /* @@ -62,7 +63,7 @@ typedef enum dof_parsed_info { * start which is the version of the dof_parseds within it. The data flowing * over the stream from the seccomped parser has no such prefix. */ -#define DOF_PARSED_VERSION 2 +#define DOF_PARSED_VERSION 3 typedef struct dof_parsed { /* @@ -147,9 +148,11 @@ typedef struct dof_parsed { */ uint32_t is_enabled; + /* V3+ only. */ /* - * XXX Not yet implemented: name, args + * Array of arg source strings. nargc in length. */ + char args[1]; } tracepoint; struct dpi_err { @@ -222,6 +225,14 @@ void usdt_parse(int out, dof_helper_t *dhp, usdt_data_t *data); */ int usdt_parse_dof(int out, dof_helper_t *dhp, dof_hdr_t *dof); +/* + * Parse probe info out of the passed-in dof_helper_t and ELF notes section + * data and emit it to OUT in the form of a stream of dof_parser_info_t. + * + * Returns 0 on success or a positive errno value on error. + */ +int usdt_parse_notes(int out, dof_helper_t *dhp, usdt_data_t *data); + /* * Shared host and parser-side. */ diff --git a/libcommon/usdt_parser_dof.c b/libcommon/usdt_parser_dof.c index 6a7eb377..bc8e185a 100644 --- a/libcommon/usdt_parser_dof.c +++ b/libcommon/usdt_parser_dof.c @@ -662,6 +662,7 @@ emit_tp(int out, uint64_t base, uint64_t offs, int is_enabled) tp.type = DIT_TRACEPOINT; tp.tracepoint.addr = base + offs; tp.tracepoint.is_enabled = is_enabled; + tp.tracepoint.args[0] = 0; usdt_parser_write_one(out, &tp, tp.size); dt_dbg_dof(" Tracepoint at 0x%lx (0x%llx + 0x%x)%s\n", diff --git a/libcommon/usdt_parser_host.c b/libcommon/usdt_parser_host.c index 2e824635..80dcf10f 100644 --- a/libcommon/usdt_parser_host.c +++ b/libcommon/usdt_parser_host.c @@ -57,7 +57,7 @@ usdt_parser_host_write(int out, const dof_helper_t *dh, const usdt_data_t *data) size_t cnt = 0; const usdt_data_t *blk; - /* Write dof_helper_t structure. */ + /* Write dof_helper_ structure. */ if ((err = usdt_parser_write_one(out, (const char *)dh, sizeof(*dh))) < 0) return err; @@ -70,8 +70,11 @@ usdt_parser_host_write(int out, const dof_helper_t *dh, const usdt_data_t *data) sizeof(cnt))) < 0) return err; - /* Write the blocks (for each, size followed by data). */ + /* Write the blocks (for each, offset, size, and data). */ for (blk = data; blk != NULL; blk = blk->next) { + if ((err = usdt_parser_write_one(out, (const char *)&blk->base, + sizeof(blk->base))) < 0) + return err; if ((err = usdt_parser_write_one(out, (const char *)&blk->size, sizeof(blk->size))) < 0) return err; diff --git a/libcommon/usdt_parser_notes.c b/libcommon/usdt_parser_notes.c new file mode 100644 index 00000000..5b7091c3 --- /dev/null +++ b/libcommon/usdt_parser_notes.c @@ -0,0 +1,774 @@ +/* + * Oracle Linux DTrace; USDT definitions parser - ELF notes. + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "usdt_parser.h" + +static void dt_dbg_usdt(const char *fmt, ...) +{ +#ifdef USDT_DEBUG + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +#endif +} + +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) + +typedef struct usdt_note { + GElf_Nhdr *hdr; + const char *name; + const char *desc; +} usdt_note_t; + +static ssize_t +get_note(int out, usdt_data_t *data, ssize_t off, usdt_note_t *note) +{ + size_t sz; + + assert(note != NULL); + + /* Validate the offset. */ + if (off >= data->size || sizeof(GElf_Nhdr) > data->size - off) { + usdt_error(out, EINVAL, "Invalid ELF note offset %zi", off); + return -1; + } + + memset(note, 0, sizeof(usdt_note_t)); + + /* Get note header and validate its alignment. */ + note->hdr = (GElf_Nhdr *)((char *)data->buf + off); + off += sizeof(GElf_Nhdr); + if (!IS_ALIGNED((uintptr_t)note->hdr, 4)) { + usdt_error(out, EINVAL, "Pointer to note header not aligned"); + return -1; + } + + dt_dbg_usdt("ELF note header { type %d, namesz %d, descsz %d }...\n", + note->hdr->n_type, note->hdr->n_namesz, + note->hdr->n_descsz); + + /* Validate the name offset and size. */ + sz = note->hdr->n_namesz; + if (off >= data->size || sz > data->size - off) { + usdt_error(out, EINVAL, "Invalid name size %d", sz); + return -1; + } + + note->name = (char *)data->buf + off; + off += ALIGN(sz, 4); + + dt_dbg_usdt("ELF note '%s' (%d bytes)\n", + note->name, note->hdr->n_descsz); + + /* Validate the desc offset and size. */ + sz = note->hdr->n_descsz; + if (off >= data->size || sz > data->size - off) { + usdt_error(out, EINVAL, "Invalid desc size %d", sz); + return -1; + } + + note->desc = (char *)data->buf + off; + off += ALIGN(sz, 4); + + /* + * If the offset reaches the end of the notes section, report this is + * as the last note. + */ + if (off >= data->size) + return 0; + + return off; +} + +typedef struct dt_provider dt_provider_t; +typedef struct dt_probe dt_probe_t; + +/* + * Defined providers are stored in a hashtable indexed on provider name. The + * probes defined in the provider are stored in pmap hashtable of the provider, + * with a NULL function name. These probes are used to validate tracepoints + * that are found in the actual code. + * + * During tracepoint validation, probes with actual fuction names will be added + * to the pmap hashtable. These probes will have tracepoint data associated + * with them, and are the probes that will be emitted as parsed data for the + * provider. Any probes that do not have tracepoints will be ignored. + * + * The dt_provider_t.probec tracks the number of probes with tracepoints. + */ +struct dt_provider { + dt_hentry_t he; + const char *name; /* provider name */ + uint32_t pattr; /* provider attributes */ + uint32_t mattr; /* module attributes */ + uint32_t fattr; /* function attributes */ + uint32_t nattr; /* probe name attributes */ + uint32_t aattr; /* argument attributes */ + uint32_t probec; /* probe count */ + dt_htab_t *pmap; /* probe hash */ +}; + +struct dt_probe { + dt_hentry_t he; + dt_probe_t *next; /* next probe in list */ + const char *prv; /* provider name */ + const char *mod; /* module name */ + const char *fun; /* function name (or NULL) */ + const char *prb; /* probe name */ + uint32_t ntp; /* number of tracepoints */ + uint32_t off; /* tracepoint offset */ + uint8_t is_enabled; /* is-enabled probe (boolean) */ + uint8_t nargc; /* native argument count */ + uint8_t xargc; /* translated argument count */ + uint8_t sargc; /* source argument count */ + const char *nargs; /* native argument types */ + size_t nargsz; /* size of native arg types */ + char *xargs; /* translated argument types */ + size_t xargsz; /* size of xlated arg types */ + uint8_t *xmap; /* translated argument map */ + const char *sargs; /* source argument strings */ +}; + +static dt_htab_t *prvmap; +static dt_htab_t *prbmap; + +extern uint32_t str2hval(const char *, uint32_t); + +static uint32_t prv_hval(const dt_provider_t *pvp) { + return str2hval(pvp->name, 0); +} + +static int prv_cmp(const dt_provider_t *p, const dt_provider_t *q) { + return strcmp(p->name, q->name); +} + +DEFINE_HE_STD_LINK_FUNCS(prv, dt_provider_t, he) +DEFINE_HTAB_STD_OPS(prv) + +static uint32_t prb_hval(const dt_probe_t *prp) { + uint32_t hval; + + hval = str2hval(prp->prv, prp->off); + hval = str2hval(prp->mod, hval); + hval = str2hval(prp->fun, hval); + + return str2hval(prp->prb, hval); +} + +static int prb_cmp(const dt_probe_t *p, const dt_probe_t *q) { + int rc; + + rc = strcmp(p->prv, q->prv); + if (rc != 0) + return rc; + + if (p->fun != NULL) { + if (q->fun == NULL) + return 1; + else { + rc = strcmp(p->fun, q->fun); + if (rc != 0) + return rc; + } + } else if (q->fun != NULL) + return -1; + + rc = strcmp(p->prb, q->prb); + if (rc != 0) + return rc; + + /* Only compare offsets when both are not zero. */ + if (p->off == 0 || q->off == 0) + + return 0; + return p->off - q->off; +} + +DEFINE_HE_STD_LINK_FUNCS(prb, dt_probe_t, he) +DEFINE_HTAB_STD_OPS(prb) + +/* + * Return the cummulative string length of 'cnt' consecutive 0-terminated + * strings. If skip > 0, it indicates how many extra bytes are to be skipped + * after the 0-byte at the end of each string. + * Return -1 if end is reached before 'cnt' strings were found. + */ +static ssize_t +strarray_size(uint8_t cnt, const char *str, const char *end, size_t skip) +{ + const char *p = str; + + while (cnt-- > 0) { + if (p >= end) + return -1; + +dt_dbg_usdt("%s: [%s] [%hhd]\n", __func__, p, *(p + strlen(p) + 1)); + p += strlen(p) + 1 + skip; + } + + return p - str; +} + +static int +parse_prov_note(int out, dof_helper_t *dhp, usdt_data_t *data, + usdt_note_t *note) +{ + const char *p = note->desc; + dt_provider_t prvt, *pvp; + const uint32_t *vals; + uint32_t probec; + int i; + + prvt.name = p; + p += ALIGN(strlen(p) + 1, 4); + if (p + 6 * sizeof(uint32_t) - note->desc > note->hdr->n_descsz) { + usdt_error(out, EINVAL, "Incomplete note data"); + return -1; + } + + if ((pvp = dt_htab_lookup(prvmap, &prvt)) == NULL) { + if ((pvp = malloc(sizeof(dt_provider_t))) == NULL) { + usdt_error(out, ENOMEM, "Failed to allocate provider"); + return -1; + } + memset(pvp, 0, sizeof(dt_provider_t)); + pvp->name = prvt.name; + dt_htab_insert(prvmap, pvp); + pvp->pmap = dt_htab_create(&prb_htab_ops); + } else { + usdt_error(out, EEXIST, "Duplicate provider: %s", prvt.name); + return -1; + } + + vals = (uint32_t *)p; + pvp->pattr = *vals++; + pvp->mattr = *vals++; + pvp->fattr = *vals++; + pvp->nattr = *vals++; + pvp->aattr = *vals++; + probec = *vals++; + + dt_dbg_usdt("[prov] %s::: with %d probe%s\n", pvp->name, probec, + probec == 1 ? "" : "s"); + + p = (char *)vals; + for (i = 0; i < probec; i++) { + int argc; + dt_probe_t prbt, *prp; + ssize_t len; + + p = (const char *)ALIGN((uintptr_t)p, 4); + prbt.prv = pvp->name; + prbt.mod = dhp->dofhp_mod; + prbt.fun = NULL; + prbt.prb = p; + prbt.off = 0; + p += strlen(p) + 1; + if (p + 2 * sizeof(uint8_t) - note->desc > note->hdr->n_descsz) { + usdt_error(out, EINVAL, "Incomplete note data"); + return -1; + } + + if ((prp = dt_htab_lookup(pvp->pmap, &prbt)) == NULL) { + if ((prp = malloc(sizeof(dt_probe_t))) == NULL) { + usdt_error(out, ENOMEM, "Failed to allocate probe"); + return -1; + } + memset(prp, 0, sizeof(dt_probe_t)); + prp->prv = prbt.prv; + prp->mod = prbt.mod; + prp->prb = prbt.prb; + prp->off = 0; + dt_htab_insert(pvp->pmap, prp); + } else { + usdt_error(out, EEXIST, "Duplicate probe: %s:%s::%s", + prbt.prv, prbt.mod, prbt.prb); + return -1; + } + + prp->next = NULL; + prp->ntp = 0; + prp->is_enabled = 0; + prp->nargc = argc = *(uint8_t *)p++; + len = strarray_size(argc, p, note->desc + note->hdr->n_descsz, + 0); + if (len == -1) { + usdt_error(out, EINVAL, "Incomplete note data"); + return -1; + } + prp->nargsz = len; + prp->nargs = p; + + p += len; + if (p - note->desc > note->hdr->n_descsz) { + usdt_error(out, EINVAL, "Incomplete note data"); + return -1; + } + + prp->xargc = argc = *(uint8_t *)p++; + len = strarray_size(argc, p, note->desc + note->hdr->n_descsz, + 1); + if (len == -1) { + usdt_error(out, EINVAL, "Incomplete note data"); + return -1; + } else if (len > 0) { + int j; + char *q; + + len -= argc; + prp->xargsz = len; + prp->xargs = q = malloc(len); + prp->xmap = malloc(argc * sizeof(uint8_t)); + if (prp->xargs == NULL || prp->xmap == NULL) { + usdt_error(out, ENOMEM, "Failed to allocate memory"); + return -1; + } + for (j = 0; j < argc; j++) { + q = stpcpy(q, p); + q++; + p += strlen(p) + 1; + prp->xmap[j] = *p; + p++; + } + } else { + prp->xargsz = 0; + prp->xargs = NULL; + } + + dt_dbg_usdt("[prov] %s:%s::%s (nargc %d, xargc %d)\n", + prp->prv, prp->mod, prp->prb, prp->nargc, + prp->xargc); + } + + return 0; +} + +static int +parse_usdt_note(int out, dof_helper_t *dhp, usdt_data_t *data, + usdt_note_t *note) +{ + const char *p = note->desc; + uint64_t off, fno; + dt_probe_t prbt, *prp; + + data = data->next; + if (data == NULL) { + usdt_error(out, EINVAL, "Missing .rodata data"); + return -1; + } + + if (p + 2 * sizeof(uint64_t) - note->desc > note->hdr->n_descsz) { + usdt_error(out, EINVAL, "Incomplete note data"); + return -1; + } + + off = *(uint64_t *)p; + p += sizeof(uint64_t); + fno = *(uint64_t *)p; + p += sizeof(uint64_t); + + prbt.prv = p; + p += strlen(p) + 1; + if (p - note->desc > note->hdr->n_descsz) { + usdt_error(out, EINVAL, "Incomplete note data"); + return -1; + } + prbt.mod = dhp->dofhp_mod; + if (fno < data->base || (fno -= data->base) >= data->size) { + usdt_error(out, EINVAL, "Invalid function name offset"); + return -1; + } + prbt.fun = (char *)data->buf + fno; + prbt.prb = p; + p += strlen(p) + 1; + if (p - note->desc > note->hdr->n_descsz) { + usdt_error(out, EINVAL, "Incomplete note data"); + return -1; + } + prbt.off = off; + + if ((prp = dt_htab_lookup(prbmap, &prbt)) == NULL) { + if ((prp = malloc(sizeof(dt_probe_t))) == NULL) { + usdt_error(out, ENOMEM, "Failed to allocate probe"); + return -1; + } + memset(prp, 0, sizeof(dt_probe_t)); + prp->prv = prbt.prv; + prp->mod = prbt.mod; + prp->fun = prbt.fun; + prp->prb = prbt.prb; + prp->off = prbt.off; + dt_htab_insert(prbmap, prp); + } else { + usdt_error(out, EEXIST, "Duplicate probe: %s:%s:%s:%s", + prbt.prv, prbt.mod, prbt.fun, prbt.prb); + return -1; + } + + prp->next = NULL; + prp->is_enabled = (note->hdr->n_type == _USDT_EN_NOTE_TYPE ? 1 : 0); + prp->ntp = 0; + prp->sargc = *p++; + prp->sargs = p; + p += strlen(p) + 1; + if (p - note->desc > note->hdr->n_descsz) { + usdt_error(out, EINVAL, "Incomplete note data"); + return -1; + } + + dt_dbg_usdt("[usdt] %s:%s:%s:%s (nargc %d, offset %lx)\n", + prp->prv, prp->mod, prp->fun, prp->prb, prp->nargc, + prp->off); + + return 0; +} + +/* + * Allocate a dof_parsed_t message structure of the given 'type', with 'len' + * extra space following the structure. The caller is responsible for calling + * free on the returned value. + * Return NULL if memory allocation failed (an error will have been emitted). + */ +static dof_parsed_t * +alloc_msg(int out, dof_parsed_info_t type, size_t len) +{ + dof_parsed_t *msg; + + switch (type) { + case DIT_PROVIDER: + len += offsetof(dof_parsed_t, provider.name); + break; + case DIT_PROBE: + len += offsetof(dof_parsed_t, probe.name); + break; + case DIT_ARGS_NATIVE: + len += offsetof(dof_parsed_t, nargs.args); + break; + case DIT_ARGS_XLAT: + len += offsetof(dof_parsed_t, xargs.args); + break; + case DIT_ARGS_MAP: + len += offsetof(dof_parsed_t, argmap.argmap); + break; + case DIT_TRACEPOINT: + len += offsetof(dof_parsed_t, tracepoint.args); + break; + default: + usdt_error(out, EINVAL, "Unknown dof_parsed_t type: %d", type); + return NULL; + } + + msg = malloc(len); + if (msg == NULL) { + usdt_error(out, ENOMEM, "Failed to allocate msg (type %d, size %ld)", + type, len); + return NULL; + } + memset(msg, 0, len); + + msg->size = len; + msg->type = type; + + return msg; +} + +static int +emit_tp(int out, const dof_helper_t *dhp, const dt_probe_t *prp) +{ + dof_parsed_t *msg; + + if ((msg = alloc_msg(out, DIT_TRACEPOINT, strlen(prp->sargs) + 1)) == NULL) + return -1; + + msg->tracepoint.addr = prp->off + dhp->dofhp_addr; + msg->tracepoint.is_enabled = prp->is_enabled; + strcpy(msg->tracepoint.args, prp->sargs); + + usdt_parser_write_one(out, msg, msg->size); + + free(msg); + + dt_dbg_usdt(" Tracepoint at 0x%lx (0x%llx + 0x%x)%s\n", + prp->off + dhp->dofhp_addr, dhp->dofhp_addr, prp->off, + prp->is_enabled ? " (is_enabled)" : ""); + + return 0; +} + +static int +emit_probe(int out, const dof_helper_t *dhp, const dt_probe_t *prp) +{ + dof_parsed_t *msg; + char *p; + + if ((msg = alloc_msg(out, DIT_PROBE, strlen(prp->mod) + 1 + + strlen(prp->fun) + 1 + + strlen(prp->prb) + 1)) == NULL) + return -1; + + msg->probe.ntp = prp->ntp; + msg->probe.nargc = prp->nargc; + msg->probe.xargc = prp->xargc; + + p = stpcpy(msg->probe.name, prp->mod); + p++; + p = stpcpy(p, prp->fun); + p++; + strcpy(p, prp->prb); + + usdt_parser_write_one(out, msg, msg->size); + + free(msg); + + dt_dbg_usdt(" Probe %s:%s:%s:%s (%d tracepoints)\n", + prp->prv, prp->mod, prp->fun, prp->prb, prp->ntp); + + /* Emit native and translated arg type data (if any). */ + if (prp->nargc) { + if ((msg = alloc_msg(out, DIT_ARGS_NATIVE, prp->nargsz)) == NULL) + return -1; + + memcpy(msg->nargs.args, prp->nargs, prp->nargsz); + + usdt_parser_write_one(out, msg, msg->size); + + free(msg); + + if (prp->xargc) { + size_t mapsz = prp->xargc * sizeof(uint8_t); + + if ((msg = alloc_msg(out, DIT_ARGS_XLAT, prp->xargsz)) == NULL) + return -1; + + memcpy(msg->xargs.args, prp->xargs, prp->xargsz); + + usdt_parser_write_one(out, msg, msg->size); + + free(msg); + + if ((msg = alloc_msg(out, DIT_ARGS_MAP, mapsz)) == NULL) + return -1; + + memcpy(msg->argmap.argmap, prp->xmap, mapsz); + + usdt_parser_write_one(out, msg, msg->size); + + free(msg); + } + } + + while (prp != NULL) { + if (emit_tp(out, dhp, prp) == -1) + return -1; + + prp = prp->next; + } + + return 0; +} + +static int +emit_provider(int out, const dof_helper_t *dhp, const dt_provider_t *pvp) +{ + dof_parsed_t *msg; + dt_htab_next_t *prbit = NULL; + dt_probe_t *prp; + + if ((msg = alloc_msg(out, DIT_PROVIDER, strlen(pvp->name) + 1)) == NULL) + return -1; + + strcpy(msg->provider.name, pvp->name); + msg->provider.nprobes = pvp->probec; + + usdt_parser_write_one(out, msg, msg->size); + + free(msg); + + dt_dbg_usdt(" Provider %s (%d probes)\n", pvp->name, pvp->probec); + + while ((prp = dt_htab_next(pvp->pmap, &prbit)) != NULL) { + if (prp->fun == NULL) + continue; + + if (emit_probe(out, dhp, prp) == -1) + return -1; + + prp = prp->next; + } + + return 0; +} + +int +usdt_parse_notes(int out, dof_helper_t *dhp, usdt_data_t *data) +{ + ssize_t off = 0; + int rc = 0; + usdt_note_t note; + dt_probe_t *ptp; + dt_htab_next_t *prbit, *prvit; + dt_provider_t *pvp; + + /* Hash tables to hold provider and probe info. */ + prvmap = dt_htab_create(&prv_htab_ops); + prbmap = dt_htab_create(&prb_htab_ops); + + /* Process all prov and usdt notes. */ + while ((off = get_note(out, data, off, ¬e)) >= 0) { + rc = -1; + if (strcmp(note.name, "prov") == 0) + rc = parse_prov_note(out, dhp, data, ¬e); + else if (strcmp(note.name, "usdt") == 0) + rc = parse_usdt_note(out, dhp, data, ¬e); + else if (strcmp(note.name, "dver") == 0 || + strcmp(note.name, "utsn") == 0) + rc = 0; /* ignore */ + else + usdt_error(out, EINVAL, "Unknown note: %s", note.name); + + if (rc == -1) + goto err; /* error emitted */ + + if (off == 0) + break; + } + + /* Bail on error. */ + if (off == -1) + goto err; + + /* + * Loop through all tracepoints (from usdt notes) and validate them + * against the registered providers and probes (from prov notes). + * Validated tracepoints are added to the provider. + */ + prbit = NULL; + while ((ptp = dt_htab_next(prbmap, &prbit)) != NULL) { + dt_provider_t prvt, *pvp; + dt_probe_t prbt, *prp; + + prvt.name = ptp->prv; + if ((pvp = dt_htab_lookup(prvmap, &prvt)) == NULL) { + usdt_error(out, ENOENT, "No such provider: %s", + ptp->prv); + goto err; + } + + /* + * First try to find a matching probe that already has one or + * more tracepoints, i.e. a probe that matches the function + * name as well. + */ + prbt.prv = ptp->prv; + prbt.mod = ptp->mod; + prbt.fun = ptp->fun; + prbt.prb = ptp->prb; + prbt.off = 0; + if ((prp = dt_htab_lookup(pvp->pmap, &prbt)) == NULL) { + /* + * Not found - make sure there is a defined probe (with + * NULL function name) that matches. + */ + prbt.fun = NULL; + if ((prp = dt_htab_lookup(pvp->pmap, &prbt)) == NULL) { + usdt_error(out, ENOENT, "No such probe: %s:::%s", + ptp->prv, ptp->prb); + goto err; + } + } + + if (ptp->sargc != prp->nargc && + (!ptp->is_enabled || ptp->sargc != 1)) { + usdt_error(out, EINVAL, + "%s:::%s%s prototype mismatch: " + "%hhd passed, %hhd expected", + ptp->prv, ptp->prb, + ptp->is_enabled ? " (is-enabled)" : "", + ptp->sargc, + ptp->is_enabled ? 1 : prp->nargc); + goto err; + } + + /* + * The tracepoint is valid. Add it to the provider. + * If there was a matching function-specific probe, add the + * tracepoint probe to it. + * If there was no matching function-specific probe, add the + * tracepoint probe to the provider. + * In either cases, argument data is copied. + */ + if (prp->fun != NULL) { + ptp->next = prp->next; + ptp->nargc = prp->nargc; + ptp->nargs = prp->nargs; + ptp->nargsz = prp->nargsz; + ptp->xargc = prp->xargc; + ptp->xargs = prp->xargs; + ptp->xargsz = prp->xargsz; + ptp->xmap = prp->xmap; + prp->next = ptp; + prp->ntp++; + } else { + dt_htab_delete(prbmap, ptp); + dt_htab_insert(pvp->pmap, ptp); + ptp->ntp = 1; + ptp->nargc = prp->nargc; + ptp->nargs = prp->nargs; + ptp->nargsz = prp->nargsz; + ptp->xargc = prp->xargc; + ptp->xargs = prp->xargs; + ptp->xargsz = prp->xargsz; + ptp->xmap = prp->xmap; + pvp->probec++; + } + } + +prvit = NULL; +while ((pvp = dt_htab_next(prvmap, &prvit)) != NULL) { + dt_htab_next_t *prbit = NULL; + dt_probe_t *prp; + + dt_dbg_usdt(" Provider '%s' with %d probe%s:\n", pvp->name, pvp->probec, pvp->probec == 1 ? "" : "s"); + while ((prp = dt_htab_next(pvp->pmap, &prbit)) != NULL) { + dt_dbg_usdt(" Probe %s:%s:%s:%s (off %x)\n", prp->prv, prp->mod, prp->fun ? prp->fun : "", prp->prb, prp->fun ? prp->off : -1); + while ((prp = prp->next) != NULL) + dt_dbg_usdt(" Probe %s:%s:%s:%s (off %x)\n", prp->prv, prp->mod, prp->fun ? prp->fun : "", prp->prb, prp->fun ? prp->off : -1); + } +} + + /* Emit any provider that has tracepoints. */ + prvit = NULL; + while ((pvp = dt_htab_next(prvmap, &prvit)) != NULL) { + if (pvp->probec > 0 && emit_provider(out, dhp, pvp) == -1) + goto err; + } + + goto out; + +err: + rc = -1; + +out: + dt_htab_destroy(prvmap); + dt_htab_destroy(prbmap); + + return rc; +} diff --git a/uts/common/sys/usdt_note_defs.h b/uts/common/sys/usdt_note_defs.h new file mode 100644 index 00000000..1501383e --- /dev/null +++ b/uts/common/sys/usdt_note_defs.h @@ -0,0 +1,18 @@ +/* + * 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. + */ + +#ifndef _SYS_USDT_NOTE_DEFS_H_ +#define _SYS_USDT_NOTE_DEFS_H_ + +#define _USDT_SECT_NAME .note.usdt +#define _USDT_TP_NOTE_NAME "usdt" /* (string constant) */ +#define _USDT_TP_NOTE_TYPE 1 /* regular probe */ +#define _USDT_EN_NOTE_TYPE 2 /* is-enabled probe */ +#define _USDT_PV_NOTE_NAME "prov" /* (string constant) */ +#define _USDT_PV_NOTE_TYPE 1 + +#endif /* _SYS_USDT_NOTE_DEFS_H_ */ -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:05 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:05 -0400 Subject: [DTrace-devel] [PATCH 14/17] usdt: implement tracing USDT probes specified in ELF notes Message-ID: --- include/dtrace/pid.h | 1 + libdtrace/dt_cg.c | 4 +- libdtrace/dt_cg.h | 3 +- libdtrace/dt_pid.c | 3 + libdtrace/dt_prov_uprobe.c | 590 +++++++++++++++++++++++++++++++++++-- 5 files changed, 573 insertions(+), 28 deletions(-) diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h index 12934500..8d4b6432 100644 --- a/include/dtrace/pid.h +++ b/include/dtrace/pid.h @@ -44,6 +44,7 @@ typedef struct pid_probespec { char *pps_xargv; /* array of xlated args */ size_t pps_xargvlen; /* (high estimate of) length of array */ int8_t *pps_argmap; /* mapped arg indexes */ + char *pps_sargv; /* list of arg sources */ /* * Fields below this point do not apply to underlying probes. diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index c68a5d45..bd0763d6 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -1597,7 +1597,7 @@ dt_cg_check_ptr_arg(dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dnp, dt_cg_check_notnull(dlp, drp, dnp->dn_reg); } -static void dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x); +void dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x); static int dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind, @@ -3006,7 +3006,7 @@ dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x) emit(dlp, instr[1]); } -static void +void dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x) { dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x); diff --git a/libdtrace/dt_cg.h b/libdtrace/dt_cg.h index fb26c125..81b79399 100644 --- a/libdtrace/dt_cg.h +++ b/libdtrace/dt_cg.h @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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. */ @@ -18,6 +18,7 @@ extern "C" { #endif extern void dt_cg(dt_pcb_t *, dt_node_t *); +extern void dt_cg_setx(dt_irlist_t *, int, uint64_t); extern void dt_cg_xsetx(dt_irlist_t *, dt_ident_t *, uint_t, int, uint64_t); extern dt_irnode_t *dt_cg_node_alloc(uint_t, struct bpf_insn); extern void dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act); diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index 9b1a2278..d12b7919 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -1077,6 +1077,9 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr, if (argmap) psp.pps_argmap = argmap; + if (tp->tracepoint.args[0] != 0) + psp.pps_sargv = tp->tracepoint.args; + dt_dprintf("providing %s:%s:%s:%s for pid %d\n", psp.pps_prv, psp.pps_mod, psp.pps_fun, psp.pps_prb, psp.pps_pid); if (pvp->impl->provide_probe(dtp, &psp) < 0) { diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index 28762eb3..cf5cfd43 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -46,6 +46,231 @@ /* Provider name for the underlying probes. */ static const char prvname[] = "uprobe"; +typedef struct asm_reg { + const char *name; /* register name */ + const char *mname; /* *pt_regs member name */ + size_t moff; /* offset in member */ + uint64_t mask; /* value mask (after shift) */ + uint8_t shift; /* value shift */ + int off; /* *pt_regs value offset */ + dt_hentry_t he; +} asm_reg_t; + +static uint32_t +reg_hval(const asm_reg_t *reg) +{ + return str2hval(reg->name, 0); +} + +static int +reg_cmp(const asm_reg_t *p, const asm_reg_t *q) +{ + return strcmp(p->name, q->name); +} + +DEFINE_HE_STD_LINK_FUNCS(reg, asm_reg_t, he) +DEFINE_HTAB_STD_OPS(reg) + +static asm_reg_t asm_regs[] = { +#if defined(__amd64) +# define REG_R(n, m) { (n), (m), 0, (-1LL), 0, 0, } +# define REG_E(n, m) { (n), (m), 0, ((1ULL << 32) - 1), 0, 0, } +# define REG_X(n, m) { (n), (m), 0, ((1ULL << 16) - 1), 0, 0, } +# define REG_L(n, m) { (n), (m), 0, ((1ULL << 8) - 1), 0, 0, } +# define REG_H(n, m) { (n), (m), 0, ((1ULL << 8) - 1), 8, 0, } + + REG_R("rax", "ax"), + REG_E("eax", "ax"), + REG_X("ax", "ax"), + REG_L("al", "ax"), + REG_H("ah", "ax"), + REG_R("rbx", "bx"), + REG_E("ebx", "bx"), + REG_X("bx", "bx"), + REG_L("bl", "bx"), + REG_H("bh", "bx"), + REG_R("rcx", "cx"), + REG_E("ecx", "cx"), + REG_X("cx", "cx"), + REG_L("cl", "cx"), + REG_H("ch", "cx"), + REG_R("rdx", "dx"), + REG_E("edx", "dx"), + REG_X("dx", "dx"), + REG_L("dl", "dx"), + REG_H("dh", "dx"), + + REG_R("rsi", "si"), + REG_E("esi", "si"), + REG_X("si", "si"), + REG_L("sil", "si"), + REG_R("rdi", "di"), + REG_E("edi", "di"), + REG_X("di", "di"), + REG_L("dil", "di"), + REG_R("rsp", "sp"), + REG_E("esp", "sp"), + REG_X("sp", "sp"), + REG_L("spl", "sp"), + REG_R("rbp", "bp"), + REG_E("ebp", "bp"), + REG_X("bp", "bp"), + REG_L("bpl", "bp"), + + REG_R("r8", "r8"), + REG_E("r8d", "r8"), + REG_X("r8w", "r8"), + REG_L("r8b", "r8"), + REG_R("r9", "r9"), + REG_E("r9d", "r9"), + REG_X("r9w", "r9"), + REG_L("r9b", "r9"), + REG_R("r10", "r10"), + REG_E("r10d", "r10"), + REG_X("r10w", "r10"), + REG_L("r10b", "r10"), + REG_R("r11", "r11"), + REG_E("r11d", "r11"), + REG_X("r11w", "r11"), + REG_L("r11b", "r11"), + REG_R("r12", "r12"), + REG_E("r12d", "r12"), + REG_X("r12w", "r12"), + REG_L("r12b", "r12"), + REG_R("r13", "r13"), + REG_E("r13d", "r13"), + REG_X("r13w", "r13"), + REG_L("r13b", "r13"), + REG_R("r14", "r14"), + REG_E("r14d", "r14"), + REG_X("r14w", "r14"), + REG_L("r14b", "r14"), + REG_R("r15", "r15"), + REG_E("r15d", "r15"), + REG_X("r15w", "r15"), + REG_L("r15b", "r15"), + + REG_R("rip", "ip"), + REG_E("eip", "ip"), + REG_X("ip", "ip"), +#elif defined(__aarch64__) +# define REG_X(n, m, i) { (n), (m), (i) * sizeof(uint64_t), (-1LL), 0, 0, } +# define REG_W(n, m, i) { (n), (m), (i) * sizeof(uint64_t), ((1ULL << 32) - 1), 0, 0, } + + REG_X("x0", "regs", 0), + REG_X("x1", "regs", 1), + REG_X("x2", "regs", 2), + REG_X("x3", "regs", 3), + REG_X("x4", "regs", 4), + REG_X("x5", "regs", 5), + REG_X("x6", "regs", 6), + REG_X("x7", "regs", 7), + REG_X("x8", "regs", 8), + REG_X("x9", "regs", 9), + REG_X("x10", "regs", 10), + REG_X("x11", "regs", 11), + REG_X("x12", "regs", 12), + REG_X("x13", "regs", 13), + REG_X("x14", "regs", 14), + REG_X("x15", "regs", 15), + REG_X("x16", "regs", 16), + REG_X("x17", "regs", 17), + REG_X("x18", "regs", 18), + REG_X("x19", "regs", 19), + REG_X("x20", "regs", 20), + REG_X("x21", "regs", 21), + REG_X("x22", "regs", 22), + REG_X("x23", "regs", 23), + REG_X("x24", "regs", 24), + REG_X("x25", "regs", 25), + REG_X("x26", "regs", 26), + REG_X("x27", "regs", 27), + REG_X("x28", "regs", 28), + REG_X("x29", "regs", 29), + REG_X("x30", "regs", 30), + + REG_W("w0", "regs", 0), + REG_W("w1", "regs", 1), + REG_W("w2", "regs", 2), + REG_W("w3", "regs", 3), + REG_W("w4", "regs", 4), + REG_W("w5", "regs", 5), + REG_W("w6", "regs", 6), + REG_W("w7", "regs", 7), + REG_W("w8", "regs", 8), + REG_W("w9", "regs", 9), + REG_W("w10", "regs", 10), + REG_W("w11", "regs", 11), + REG_W("w12", "regs", 12), + REG_W("w13", "regs", 13), + REG_W("w14", "regs", 14), + REG_W("w15", "regs", 15), + REG_W("w16", "regs", 16), + REG_W("w17", "regs", 17), + REG_W("w18", "regs", 18), + REG_W("w19", "regs", 19), + REG_W("w20", "regs", 20), + REG_W("w21", "regs", 21), + REG_W("w22", "regs", 22), + REG_W("w23", "regs", 23), + REG_W("w24", "regs", 24), + REG_W("w25", "regs", 25), + REG_W("w26", "regs", 26), + REG_W("w27", "regs", 27), + REG_W("w28", "regs", 28), + REG_W("w29", "regs", 29), + REG_W("w30", "regs", 30), + + REG_X("sp", "sp", 0), + REG_X("pc", "sp", 0), + + REG_X("lr", "regs", 30), +#else +# error ISA not supported +#endif +}; + +static asm_reg_t * +get_asm_reg(dt_provider_t *pvp, const char *name) +{ + dt_htab_t *rtab = pvp->prv_data; + asm_reg_t regt; + + if (rtab == NULL) { + int i; + asm_reg_t *rp, *reg = NULL; + + rtab = dt_htab_create(®_htab_ops); + if (rtab == NULL) + return NULL; + + pvp->prv_data = rtab; + + for (i = 0, rp = asm_regs; i < ARRAY_SIZE(asm_regs); + i++, rp++) { +#if defined(__amd64) + rp->off = dt_cg_ctf_offsetof("struct pt_regs", + rp->mname, NULL, 0) + + rp->moff; +#elif defined(__aarch64__) + rp->off = dt_cg_ctf_offsetof("struct user_pt_regs", + rp->mname, NULL, 0) + + rp->moff; +#endif + + if (dt_htab_insert(rtab, rp) < 0) + return NULL; + if (strcmp(rp->name, name) == 0) + reg = rp; + } + + return reg; + } + + regt.name = name; + return dt_htab_lookup(rtab, ®t); +} + #define PP_IS_RETURN 0x1 #define PP_IS_FUNCALL 0x2 #define PP_IS_ENABLED 0x4 @@ -55,15 +280,17 @@ static const char prvname[] = "uprobe"; typedef struct dt_uprobe { dev_t dev; ino_t inum; - char *fn; /* object full file name */ - char *func; /* function */ + char *fn; /* object full file name */ + char *func; /* function */ uint64_t off; int flags; tp_probe_t *tp; - int argc; /* number of args */ - dt_argdesc_t *args; /* args array (points into argvbuf) */ - char *argvbuf; /* arg strtab */ - dt_list_t probes; /* pid/USDT probes triggered by it */ + int argc; /* number of args */ + dt_argdesc_t *args; /* args array (points into argvbuf) */ + char *argvbuf; /* arg strtab */ + int sargc; /* number of arg source specs */ + char *sargv; /* arg source specs */ + dt_list_t probes; /* pid/USDT probes triggered by it */ } dt_uprobe_t; typedef struct list_probe { @@ -132,6 +359,7 @@ static void probe_destroy_underlying(dtrace_hdl_t *dtp, void *datap) dt_free(dtp, upp->func); dt_free(dtp, upp->args); dt_free(dtp, upp->argvbuf); + dt_free(dtp, upp->sargv); dt_free(dtp, upp); } @@ -290,15 +518,19 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp) * status in the clause flags for dt_stmts[n]. */ if (dt_stmt_clsflag_test(stp, DT_CLSFLAG_USDT_INCLUDE | DT_CLSFLAG_USDT_EXCLUDE) == 0) { - char lastchar = pdp->prv[strlen(pdp->prv) - 1]; + size_t len = strlen(pdp->prv); /* * If the last char in the provider description is * neither '*' nor a digit, it cannot be a USDT probe. */ - if (lastchar != '*' && !isdigit(lastchar)) { - dt_stmt_clsflag_set(stp, DT_CLSFLAG_USDT_EXCLUDE); - return 1; + if (len > 1) { + char lastchar = pdp->prv[len - 1]; + + if (lastchar != '*' && !isdigit(lastchar)) { + dt_stmt_clsflag_set(stp, DT_CLSFLAG_USDT_EXCLUDE); + return 1; + } } /* @@ -340,6 +572,17 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp) return 0; } +static void usdt_error(dt_pcb_t *pcb, const char *fmt, ...) +{ + dtrace_hdl_t *dtp = pcb->pcb_hdl; + va_list ap; + + va_start(ap, fmt); + dt_set_errmsg(dtp, NULL, NULL, NULL, 0, fmt, ap); + va_end(ap); + longjmp(pcb->pcb_jmpbuf, EDT_COMPILER); +} + static int add_probe_uprobe(dtrace_hdl_t *dtp, dt_probe_t *prp) { dtrace_difo_t *dp; @@ -539,6 +782,18 @@ static int populate_args(dtrace_hdl_t *dtp, const pid_probespec_t *psp, upp->argc = psp->pps_xargc; + /* Copy argument value source string data (if any). */ + if (psp->pps_sargv) { + /* + * Is-enabled probes have one (internal use only) argument. + * They retain the narg/xarg data from the probe they are + * associated with, for consistency, but that data will not be + * used. + */ + upp->sargc = (upp->flags & PP_IS_ENABLED) ? 1 : psp->pps_nargc; + upp->sargv = strdup(psp->pps_sargv); + } + /* * If we have a nonzero number of args, we always have at least one narg * and at least one xarg. Double-check to be sure. (These are not @@ -700,9 +955,6 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, assert(strcmp(upp->func, psp->pps_fun) == 0); } - if (populate_args(dtp, psp, upp) < 0) - goto fail; - switch (psp->pps_type) { case DTPPT_RETURN: upp->flags |= PP_IS_RETURN; @@ -719,6 +971,9 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, */ } + if (populate_args(dtp, psp, upp) < 0) + goto fail; + return uprp; fail: @@ -889,6 +1144,289 @@ static void enable_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp) enable(dtp, prp, 1); } +/* + * Generate code that populates the probe arguments. + */ +static void copy_args(dt_pcb_t *pcb, const dt_uprobe_t *upp) +{ + dtrace_hdl_t *dtp = pcb->pcb_hdl; + dt_irlist_t *dlp = &pcb->pcb_ir; + dt_provider_t *pvp = dt_provider_lookup(dtp, dt_usdt.name); + asm_reg_t *areg; + int i; + char *p = upp->sargv; + + assert(pvp != NULL); + + for (i = 0; i < upp->sargc; i++) { + int ssize, disp, len; + char *reg = NULL; + int64_t val = 0; + + /* + * Get sign/size. Missing sign/size is an error. + * Also, float is not supported. + */ + ssize = 0; + len = -1; + if (sscanf(p, " %d @ %n", &ssize, &len) <= 0 || len == -1) + usdt_error(pcb, "Missing sign/size in arg%d spec", i); + + p += len; + + /* Look for dereference (with optional displacement). */ + disp = 0; + len = -1; +#ifdef __aarch64__ + if (sscanf(p, "[ %m[^],] %n", ®, &len) > 0 && len > 0) { + char *ireg = NULL; + + p += len; + + if (*p != ']') { + /* Expect a displacement or index register. */ + if (sscanf(p, ", %n", &len) < 0) + usdt_error(pcb, "Expected , in arg%d spec", i); + + p += len; + + if (sscanf(p, "%d ] %n", &disp, &len) != 1 && + sscanf(p, "%m[^],] , %d ] %n", &ireg, &disp, + &len) != 2 && + sscanf(p, "%m[^]] ] %n", &ireg, &len) != 1) + usdt_error(pcb, "Missing displacement and/or index register in arg%d spec", i); + } else + sscanf(p, "] %n", &len); + + p += len; + + /* + * If there is an index register, put its value in %r1 + * (after applying the scale if specified). + */ + if (ireg != NULL) { + areg = get_asm_reg(pvp, ireg); + if (areg == NULL) + usdt_error(pcb, "Unknown index register %s in arg%d spec", ireg, i); + + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, areg->off)); + } + + /* If there is a base register, get its value. */ + if (reg != NULL) { + int neg = 0; + int shift; + + if (ssize < 0) { + neg = 1; + ssize = -ssize; + } + + shift = 64 - ssize * 8; + + areg = get_asm_reg(pvp, reg); + if (areg == NULL) + usdt_error(pcb, "Unknown base register %s in arg%d spec", reg, i); + + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, areg->off)); + + if (ireg != NULL) + emit(dlp, BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1)); + + if (disp != 0) + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, disp)); + + /* Load value from the pointer. */ + 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, ssize)); + emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user])); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(i))); + if (shift) { + emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift)); + emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift)); + } + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + } else { + if (disp != 0) + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, disp)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_1)); + } + + free(reg); + free(ireg); + } else if (sscanf(p, "%ld %n", &val, &len) > 0) { + /* Handle constant value. */ + p += len; + + if (val > (1ULL << 32) - 1ULL) { + dt_cg_setx(dlp, BPF_REG_0, val); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + } else + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), val)); + } else if (sscanf(p, "%m[a-z0-9] %n", ®, &len) > 0) { + /* Handle simple register. */ + int neg = 0; + int shift; + uint_t sz; + + if (ssize < 0) { + neg = 1; + ssize = -ssize; + } + + shift = 64 - ssize * 8; + sz = bpf_ldst_size(ssize, 1); + + areg = get_asm_reg(pvp, reg); + if (areg == NULL) + usdt_error(pcb, "Unknown register %s in arg%d spec", reg, i); + + emit(dlp, BPF_LOAD(sz, BPF_REG_0, BPF_REG_8, areg->off)); + if (shift) { + emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift)); + emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift)); + } + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + + free(reg); + p += len; + } else + usdt_error(pcb, "Unknown format in arg%d spec", i); +#else + if ((sscanf(p, "%d ( %n", &disp, &len) == 1 || + sscanf(p, "( %n", &len) == 0) && len >= 0) { + char *ireg = NULL; + int scale = -1; + + p += len; + + if (*p != ',') { + /* Expect a base register. */ + if (sscanf(p, "%%%m[^,)] %n", ®, &len) <= 0) + usdt_error(pcb, "Missing base register in arg%d spec", i); + + p += len; + } + + if (*p != ')') { + /* Expect an index register. */ + if (sscanf(p, ", %%%m[^,)] %n", &ireg, &len) <= 0) + usdt_error(pcb, "Missing index register in arg%d spec", i); + + p += len; + + /* Expect scale or closing parenthesis. */ + len = 0; + if (sscanf(p, ", %d ) %n", &scale, &len) <= 0 && + sscanf(p, ") %n", &len) < 0) + usdt_error(pcb, "Missing scale or ) in arg%d spec", i); + } else + sscanf(p, ") %n", &len); + + p += len; + + /* + * If there is an index register, put its value in %r1 + * (after applying the scale if specified). + */ + if (ireg != NULL) { + areg = get_asm_reg(pvp, ireg); + if (areg == NULL) + usdt_error(pcb, "Unknown index register %s in arg%d spec", ireg, i); + + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, areg->off)); + if (scale > 0) + emit(dlp, BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, scale)); + } + + /* If there is a base register, get its value. */ + if (reg != NULL) { + int neg = 0; + int shift; + + if (ssize < 0) { + neg = 1; + ssize = -ssize; + } + + shift = 64 - ssize * 8; + + areg = get_asm_reg(pvp, reg); + if (areg == NULL) + usdt_error(pcb, "Unknown base register %s in arg%d spec", reg, i); + + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, areg->off)); + + if (ireg != NULL) + emit(dlp, BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1)); + + if (disp != 0) + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, disp)); + + /* Load value from the pointer. */ + 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, ssize)); + emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user])); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(i))); + if (shift) { + emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift)); + emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift)); + } + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + } else { + if (disp != 0) + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, disp)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_1)); + } + + free(reg); + free(ireg); + } else if (sscanf(p, "%%%ms %n", ®, &len) > 0) { + /* Handle simple register. */ + int neg = 0; + int shift; + uint_t sz; + + if (ssize < 0) { + neg = 1; + ssize = -ssize; + } + + shift = 64 - ssize * 8; + sz = bpf_ldst_size(ssize, 1); + + areg = get_asm_reg(pvp, reg); + if (areg == NULL) + usdt_error(pcb, "Unknown register %s in arg%d spec", reg, i); + + emit(dlp, BPF_LOAD(sz, BPF_REG_0, BPF_REG_8, areg->off)); + if (shift) { + emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift)); + emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift)); + } + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + + free(reg); + p += len; + } else if (sscanf(p, "$%ld %n", &val, &len) > 0) { + /* Handle constant value. */ + p += len; + + if (val > (1ULL << 32) - 1ULL) { + dt_cg_setx(dlp, BPF_REG_0, val); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + } else + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), val)); + } else + usdt_error(pcb, "Unknown format in arg%d spec", i); +#endif + } +} + /* * Generate a BPF trampoline for a pid or USDT probe. * @@ -981,17 +1519,10 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) if (upp->flags & PP_IS_RETURN) goto out; - dt_cg_tramp_copy_args_from_regs(pcb, 0); - - /* - * Apply arg mappings, if needed. - */ - if (upp->flags & PP_IS_MAPPED) { - - /* dt_cg_tramp_map_args() works from the saved args. */ - dt_cg_tramp_save_args(pcb); - dt_cg_tramp_map_args(pcb, upp->args, upp->argc); - } + if (upp->sargc) + copy_args(pcb, upp); + else + dt_cg_tramp_copy_args_from_regs(pcb, 0); /* * Retrieve the PID of the process that caused the probe to fire. @@ -1022,7 +1553,7 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) * The trampoline writes 1 into the location pointed to by the passed-in arg. */ emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_FP, DT_TRAMP_SP_SLOT(0), 1)); - emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, PT_REGS_ARG0)); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(0))); emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_FP)); emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_MOV_IMM(BPF_REG_3, sizeof(uint32_t))); @@ -1042,6 +1573,15 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) /* Read the bit mask from the table lookup in %r6. */ // FIXME someday, extend this past 64 bits emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_0, offsetof(usdt_prids_map_val_t, mask))); + /* + * Apply arg mappings, if needed. + */ + if (upp->flags & PP_IS_MAPPED) { + /* dt_cg_tramp_map_args() works from the saved args. */ + dt_cg_tramp_save_args(pcb); + dt_cg_tramp_map_args(pcb, upp->args, upp->argc); + } + /* * Hold the bit mask in %r6 between clause calls. */ -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:07 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:07 -0400 Subject: [DTrace-devel] [PATCH 16/17] test: fix test for non-installed testing Message-ID: On a system without DTrace installed, cannot be found, causing this test to fail. Use test_cppflags to ensure the correct location is used in all cases. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock --- test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh b/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh index f66d6cbd..f80fcc05 100755 --- a/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh +++ b/test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh @@ -22,7 +22,7 @@ if [ $# != 1 ]; then fi dtrace=$1 -CFLAGS= +CFLAGS=${test_cppflags} DIRNAME="$tmpdir/list-probes-module-usdt.$$.$RANDOM" mkdir -p $DIRNAME -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:07 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:07 -0400 Subject: [DTrace-devel] [PATCH 17/17] test: Adapt USDT PC search for USDT LTO changes Message-ID: To check USDT PCs, we looked at disassembly for characteristics that indicated USDT probes. With LTO, however, USDT instrumentation has changed. Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. Note that tst.pidargs.sh and tst.pidargmap.sh depend on tst.pidprobes.sh. Therefore, those tests also benefit from this change. They do not yet pass, however, since index 0 for args[] is said to be out of range. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees --- test/unittest/usdt/tst.pidprobes.sh | 114 ++++++++++------------------ 1 file changed, 39 insertions(+), 75 deletions(-) diff --git a/test/unittest/usdt/tst.pidprobes.sh b/test/unittest/usdt/tst.pidprobes.sh index 72434eb9..24fbd518 100755 --- a/test/unittest/usdt/tst.pidprobes.sh +++ b/test/unittest/usdt/tst.pidprobes.sh @@ -19,6 +19,7 @@ mapping=${3:-} # Set up test directory. +d=`pwd` DIRNAME=$tmpdir/pidprobes.$$.$RANDOM mkdir -p $DIRNAME cd $DIRNAME @@ -74,9 +75,6 @@ if [ $? -ne 0 ]; then echo "failed to compile test" >&2 exit 1 fi -if [[ `uname -m` = "aarch64" ]]; then - $OBJDUMP -d main.o > disasm_foo.txt.before -fi $dtrace $dt_flags -G -64 -s prov.d main.o if [ $? -ne 0 ]; then echo "failed to create DOF" >&2 @@ -183,84 +181,50 @@ if [ `awk 'NF != 0 { print $1 }' dtrace.out | uniq | wc -l` -ne 1 ]; then fi pid=`awk 'NF != 0 { print $1 }' dtrace.out | uniq` -# From the disassembly, get the PCs for USDT probes. -# Check libdtrace/dt_link.c's arch-dependent dt_modtext() to see -# what sequence of instructions signal a USDT probe. - -if [[ `uname -m` = "x86_64" ]]; then - - # It is the first of five nop instructions in a row. - # So track pc[-6], pc[-5], pc[-4], pc[-3], pc[-2], pc[-1], pc[0] - # as well as whether they are nop. - - usdt_pcs_all=`awk ' - BEGIN { - pc6 = -1; is_nop6 = 0; - pc5 = -1; is_nop5 = 0; - pc4 = -1; is_nop4 = 0; - pc3 = -1; is_nop3 = 0; - pc2 = -1; is_nop2 = 0; - pc1 = -1; is_nop1 = 0; +# From showUSDT output, get the PCs for USDT probes. We look for output like: +# Note usdt, type N: +# Offset 0xoffset +# Function Offset 0xfoffset +# Probe pyramid::foo:entry +$d/test/utils/showUSDT main | awk ' +/^ *Note usdt, type / { + getline; + if (!match($0, /^ *Offset *0x[0-9a-f]* *$/)) { + print "ERROR: expect Offset"; + exit(1); } - { - # pc0 is current instruction - pc0 = strtonum("0x"$1); - - # decide whether it is a nop - is_nop0 = 0; - if (NF == 3 && - $2 == "90" && - $3 == "nop") - is_nop0 = 1; - - # report if pc[-5] is a USDT instruction - if (is_nop6 == 0 && - is_nop5 == 1 && - is_nop4 == 1 && - is_nop3 == 1 && - is_nop2 == 1 && - is_nop1 == 1 && - is_nop0 == 0) - print pc5; - - # prepare advance to next instruction - pc6 = pc5; is_nop6 = is_nop5; - pc5 = pc4; is_nop5 = is_nop4; - pc4 = pc3; is_nop4 = is_nop3; - pc3 = pc2; is_nop3 = is_nop2; - pc2 = pc1; is_nop2 = is_nop1; - pc1 = pc0; is_nop1 = is_nop0; - }' disasm_foo.txt` - - # We expect 4 USDT probes (2 USDT and 2 is-enabled). - if [ `echo $usdt_pcs_all | awk '{print NF}'` -ne 4 ]; then - echo ERROR: expected 4 USDT probes but got $usdt_pcs_all - cat disasm_foo.txt - exit 1 - fi + off = strtonum($2); - # Separate them into regular and is-enabled PCs. - # We assume they alternate. - usdt_pcs=`echo $usdt_pcs_all | awk '{ print $1, $3 }'` - usdt_pcs_isenabled=`echo $usdt_pcs_all | awk '{ print $2, $4 }'` + getline; + if (!match($0, /^ *Function Offset *0x[0-9a-f]* *$/)) { + print "ERROR: expect Function Offset"; + exit(1); + } -elif [[ `uname -m` = "aarch64" ]]; then + getline; + if (!match($0, /^ *Probe pyramid::foo:entry/)) { + print "ERROR: expect Probe pyramid::foo:entry"; + exit(1); + } - # The initial compilation of foo() makes it obvious where the - # USDT probes are. We just have to add the function offset in. - usdt_pcs=`awk '/<__dtrace_pyramid___entry>/ { print strtonum("0x"$1) + '$pc0' }' disasm_foo.txt.before` - usdt_pcs_isenabled=`awk '/<__dtraceenabled_pyramid___entry>/ { print strtonum("0x"$1) + '$pc0' }' disasm_foo.txt.before` + print off, $0; +} ' > usdt_pcs.txt +if [ $? -ne 0 ]; then + echo ERROR: showUSDT output to awk + $d/test/utils/showUSDT main + exit 1 +fi +usdt_pcs=`awk '!/is-enabled/ { sub("0x", ""); print $1}' usdt_pcs.txt` +usdt_pcs_isenabled=`awk '/is-enabled/ { sub("0x", ""); print $1}' usdt_pcs.txt` - # We expect 4 USDT probes (2 USDT and 2 is-enabled). - if [ `echo $usdt_pcs | awk '{print NF}'` -ne 2 -o \ - `echo $usdt_pcs_isenabled | awk '{print NF}'` -ne 2 ]; then - echo ERROR: expected 4 USDT probes but got $usdt_pcs and $usdt_pcs_isenabled - cat disasm_foo.txt.before - exit 1 - fi +# We expect 2 USDT probes plus 2 is-enabled. -else - echo ERROR unrecognized machine hardware name +if [ `echo $usdt_pcs | awk '{print NF}'` -ne 2 ]; then + echo ERROR: expected 2 USDT regular probes but got $usdt_pcs + exit 1 +fi +if [ `echo $usdt_pcs_isenabled | awk '{print NF}'` -ne 2 ]; then + echo ERROR: expected 2 USDT is-enabled probes but got $usdt_pcs_isenabled exit 1 fi -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 06:15:06 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 02:15:06 -0400 Subject: [DTrace-devel] [PATCH 15/17] link: implement USDT probe definitions in ELF notes Message-ID: Signed-off-by: Kris Van Hees --- libdtrace/drti.c | 131 +- libdtrace/dt_dof.c | 13 +- libdtrace/dt_impl.h | 8 +- libdtrace/dt_link.c | 1803 ++++------------- libdtrace/dt_program.c | 48 +- test/triggers/Build | 19 +- test/triggers/usdt-tst-arg-const-prov.d | 19 + test/triggers/usdt-tst-arg-const.c | 25 + test/triggers/usdt-tst-arg-reg-prov.d | 19 + test/triggers/usdt-tst-arg-reg.c | 35 + test/triggers/usdt-tst-deref-decode-prov.d | 11 + test/triggers/usdt-tst-deref-decode.aarch64.c | 84 + test/triggers/usdt-tst-deref-decode.x86_64.c | 80 + test/unittest/options/tst.strip.sh | 8 +- ....guess32.sh => err.wrong-probe-argc-cc.sh} | 44 +- test/unittest/usdt/err.wrong-probe-argc-rt.sh | 59 + test/unittest/usdt/err.wrong-probe.sh | 59 + test/unittest/usdt/err.wrong-prov.sh | 59 + test/unittest/usdt/tst.arg-reg.d | 38 + test/unittest/usdt/tst.arg-reg.r | 9 + test/unittest/usdt/tst.badguess.sh | 63 - test/unittest/usdt/tst.badguess.x | 7 - test/unittest/usdt/tst.const.d | 38 + test/unittest/usdt/tst.const.r | 9 + test/unittest/usdt/tst.deref-decode.d | 39 + test/unittest/usdt/tst.guess32.x | 8 - .../usdt/tst.multiprov-dupprobe-shlibs.r.p | 4 + test/utils/Build | 6 +- test/utils/showUSDT.c | 370 +++- uts/common/sys/sdt.h | 163 +- uts/common/sys/usdt.h | 83 + uts/common/sys/usdt_gennote.h | 139 ++ uts/common/sys/usdt_internal.h | 245 +++ 33 files changed, 1856 insertions(+), 1889 deletions(-) create mode 100644 test/triggers/usdt-tst-arg-const-prov.d create mode 100644 test/triggers/usdt-tst-arg-const.c create mode 100644 test/triggers/usdt-tst-arg-reg-prov.d create mode 100644 test/triggers/usdt-tst-arg-reg.c create mode 100644 test/triggers/usdt-tst-deref-decode-prov.d create mode 100644 test/triggers/usdt-tst-deref-decode.aarch64.c create mode 100644 test/triggers/usdt-tst-deref-decode.x86_64.c rename test/unittest/usdt/{tst.guess32.sh => err.wrong-probe-argc-cc.sh} (57%) create mode 100755 test/unittest/usdt/err.wrong-probe-argc-rt.sh create mode 100755 test/unittest/usdt/err.wrong-probe.sh create mode 100755 test/unittest/usdt/err.wrong-prov.sh create mode 100644 test/unittest/usdt/tst.arg-reg.d create mode 100644 test/unittest/usdt/tst.arg-reg.r delete mode 100755 test/unittest/usdt/tst.badguess.sh delete mode 100755 test/unittest/usdt/tst.badguess.x create mode 100644 test/unittest/usdt/tst.const.d create mode 100644 test/unittest/usdt/tst.const.r create mode 100644 test/unittest/usdt/tst.deref-decode.d delete mode 100755 test/unittest/usdt/tst.guess32.x create mode 100644 uts/common/sys/usdt.h create mode 100644 uts/common/sys/usdt_gennote.h create mode 100644 uts/common/sys/usdt_internal.h diff --git a/libdtrace/drti.c b/libdtrace/drti.c index 52a47061..ca512cb0 100644 --- a/libdtrace/drti.c +++ b/libdtrace/drti.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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. */ @@ -34,11 +34,8 @@ static const char *devname = "/dev/dtrace/helper"; -static const char *modname; /* Name of this load object */ static int gen; /* DOF helper generation */ -extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */ static boolean_t dof_init_debug = B_FALSE; /* From DTRACE_DOF_INIT_DEBUG */ -static dof_helper_t dh; static char *errmsg_open, *errmsg_ioctl_failed, *errmsg_ioctl_ok; @@ -71,19 +68,7 @@ _dt_constructor_(dtrace_dof_init) static void dtrace_dof_init(void) { - dof_hdr_t *dof = &__SUNW_dof; -#ifdef _LP64 - Elf64_Ehdr *elf; -#else - Elf32_Ehdr *elf; -#endif - struct link_map *lmp = NULL; - Lmid_t lmid = -1; const char *p; - char str[4096]; /* read buffer */ - char *enm = NULL; /* pointer to target executable name */ - FILE *fp; - struct link_map fmap = { 0x0, }; if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL) return; @@ -94,116 +79,11 @@ dtrace_dof_init(void) if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL) devname = p; -#if 0 - if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1) { - dprintf(2, "DRTI: Couldn't discover module name or address.\n"); - return; - } - - if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) { - dprintf(2, "DRTI: Couldn't discover link map ID.\n"); - return; - } -#else - lmid = 0; /* We need a way to determine this. */ - - if ((fp = fopen("/proc/self/maps", "re")) == NULL) { - dprintf(2, "DRTI: Failed to open maps file.\n"); - return; - } - while (fgets(str, sizeof(str), fp) != NULL) { - uintptr_t start, end; - char *p = str, *q; - - start = strtoul(p, &p, 16); - if (*p != '-') - continue; - - end = strtoul(++p, &p, 16); - - if (start > (uintptr_t)dtrace_dof_init || - (uintptr_t)dtrace_dof_init > end) - continue; - - if ((p = strrchr(str, ' ')) == NULL) - continue; - p++; /* move past the leading space char */ - if ((q = strchr(p, '\n')) != NULL) - *q = '\0'; - enm = strdup(p); /* Save name of object w/ dtrace_dof_init */ - break; - } - - if (_dt_unlikely_(enm == NULL)) { - fclose(fp); - dprintf(2, "DRTI: Couldn't discover module name or address.\n"); - return; - } - - /* Now start at the beginning & look for 1st segment of the target */ - rewind(fp); - while (fgets(str, sizeof(str), fp) != NULL) { - uintptr_t start; - char *p = str, *q; - - start = strtoul(p, &p, 16); - if (*p != '-') - continue; - if ((p = strrchr(str, ' ')) == NULL) - continue; - p++; /* move past the leading space char */ - if ((q = strchr(p, '\n')) != NULL) - *q = '\0'; - - /* If found the 1st segment of the target executable */ - if (strcmp(enm, p) == 0) { - fmap.l_addr = start; /* record start address */ - fmap.l_name = p; - lmp = &fmap; - break; - } - } - free(enm); - fclose(fp); -#endif - if (_dt_unlikely_(lmp == NULL)) { - dprintf(2, "DRTI: Couldn't discover module name or address.\n"); - return; - } - - if ((modname = strrchr(lmp->l_name, '/')) == NULL) - modname = lmp->l_name; - else - modname++; - - if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 || - dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 || - dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 || - dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) { - dprintf(2, "DRTI: .SUNW_dof section corrupt in %s.\n", - lmp->l_name); - return; - } - - elf = (void *)lmp->l_addr; - - dh.dofhp_dof = (uintptr_t)dof; - dh.dofhp_addr = elf->e_type == ET_DYN ? lmp->l_addr : 0; - - if (lmid == 0) { - (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), - "%s", modname); - } else { - (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), - "LM%lu`%s", lmid, modname); - } - /* * Prep error messages to avoid non-async-signal-safe printfs inside * dtrace_dof_register(). */ - if (asprintf(&errmsg_ioctl_failed, "DRTI: Ioctl failed for DOF at %llx\n", - (long long unsigned) dh.dofhp_addr) < 0) + if (asprintf(&errmsg_ioctl_failed, "DRTI: Ioctl failed\n") < 0) errmsg_ioctl_failed = NULL; if (dof_init_debug) { @@ -211,8 +91,8 @@ dtrace_dof_init(void) devname) < 0) errmsg_open = NULL; - if (asprintf(&errmsg_ioctl_ok, "DRTI: Ioctl OK for DOF at %llx (gen %d)\n", - (long long unsigned) dh.dofhp_addr, gen) < 0) + if (asprintf(&errmsg_ioctl_ok, "DRTI: Ioctl OK (gen %d)\n", + gen) < 0) errmsg_ioctl_ok = NULL; } @@ -231,7 +111,8 @@ dtrace_dof_register(void) return; } - if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1) { + gen = ioctl(fd, DTRACEHIOC_HASUSDT, (uintptr_t)dtrace_dof_init); + if (gen == -1) { if (errmsg_ioctl_failed) write(2, errmsg_ioctl_failed, strlen(errmsg_ioctl_failed)); diff --git a/libdtrace/dt_dof.c b/libdtrace/dt_dof.c index 9e5c3e1e..056fb646 100644 --- a/libdtrace/dt_dof.c +++ b/libdtrace/dt_dof.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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. */ @@ -362,6 +362,17 @@ dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) dofpr.dofpr_pad1 = 0; dofpr.dofpr_pad2 = 0; + if (prp->pr_inst == NULL) { + dofpr.dofpr_func = 0; + dofpr.dofpr_offidx = 0; + dofpr.dofpr_noffs = 0; + dofpr.dofpr_enoffidx = 0; + dofpr.dofpr_nenoffs = 0; + + dt_buf_write(dtp, &ddo->ddo_probes, &dofpr, + sizeof(dofpr), sizeof(uint64_t)); + } + for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) { dt_dprintf("adding probe for %s:%s\n", pip->pi_fname, prp->pr_name); diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h index 68fb8ec5..3bb7c344 100644 --- a/libdtrace/dt_impl.h +++ b/libdtrace/dt_impl.h @@ -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. */ @@ -52,7 +52,11 @@ extern "C" { #include #ifndef ARRAY_SIZE -# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +#ifndef ALIGN +# define ALIGN(n, p2) (((n) + (p2) - 1) & ~((p2) - 1)) #endif #ifndef __stringify diff --git a/libdtrace/dt_link.c b/libdtrace/dt_link.c index b2148a8b..c9e0ea5f 100644 --- a/libdtrace/dt_link.c +++ b/libdtrace/dt_link.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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. */ @@ -30,1464 +30,383 @@ #include #include #include +#include -#define ESHDR_NULL 0 -#define ESHDR_SHSTRTAB 1 -#define ESHDR_STACKNOTE 2 -#define ESHDR_DOF 3 -#define ESHDR_STRTAB 4 -#define ESHDR_SYMTAB 5 -#define ESHDR_REL 6 -#define ESHDR_NUM 7 - -#define PWRITE_SCN(index, data) \ - (lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \ - (off64_t)elf_file.shdr[(index)].sh_offset || \ - dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \ - elf_file.shdr[(index)].sh_size) - -static const char DTRACE_SHSTRTAB32[] = "\0" -#define NAMEOFF_SHSTRTAB 1 - ".shstrtab\0" /* 1 */ -#define NAMEOFF_STACKNOTE 11 - ".note.GNU-stack\0" /* 11 */ -#define NAMEOFF_DOF 27 - ".SUNW_dof\0" /* 27 */ -#define NAMEOFF_STRTAB 37 - ".strtab\0" /* 37 */ -#define NAMEOFF_SYMTAB 45 - ".symtab\0" /* 45 */ -#define NAMEOFF_REL 53 -#ifdef __sparc - ".rela.SUNW_dof"; /* 53 */ -#else - ".rel.SUNW_dof"; /* 53 */ -#endif - -static const char DTRACE_SHSTRTAB64[] = "\0" - ".shstrtab\0" /* 1 */ - ".note.GNU-stack\0" /* 11 */ - ".SUNW_dof\0" /* 27 */ - ".strtab\0" /* 37 */ - ".symtab\0" /* 45 */ - ".rela.SUNW_dof"; /* 53 */ - -static const char DOFSTR[] = "__SUNW_dof"; -static const char DOFLAZYSTR[] = "___SUNW_dof"; - -typedef struct dt_link_pair { - struct dt_link_pair *dlp_next; /* next pair in linked list */ - void *dlp_str; /* buffer for string table */ - void *dlp_sym; /* buffer for symbol table */ -} dt_link_pair_t; - -typedef struct dof_elf32 { - uint32_t de_nrel; /* relocation count */ -#ifdef __sparc - Elf32_Rela *de_rel; /* array of relocations for sparc */ -#else - Elf32_Rel *de_rel; /* array of relocations for x86 */ -#endif - uint32_t de_nsym; /* symbol count */ - Elf32_Sym *de_sym; /* array of symbols */ - uint32_t de_strlen; /* size of of string table */ - char *de_strtab; /* string table */ - uint32_t de_global; /* index of the first global symbol */ -} dof_elf32_t; - -static int -prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep) -{ - dof_sec_t *dofs, *s; - dof_relohdr_t *dofrh; - dof_relodesc_t *dofr; - char *strtab; - int i, j, nrel; - size_t strtabsz = 1; - uint32_t count = 0; - size_t base; - Elf32_Sym *sym; -#ifdef __sparc - Elf32_Rela *rel; -#else - Elf32_Rel *rel; -#endif - - /*LINTED*/ - dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); - - /* - * First compute the size of the string table and the number of - * relocations present in the DOF. - */ - for (i = 0; i < dof->dofh_secnum; i++) { - if (dofs[i].dofs_type != DOF_SECT_URELHDR) - continue; - - /*LINTED*/ - dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); - - s = &dofs[dofrh->dofr_strtab]; - strtab = (char *)dof + s->dofs_offset; - assert(strtab[0] == '\0'); - strtabsz += s->dofs_size - 1; - - s = &dofs[dofrh->dofr_relsec]; - /*LINTED*/ - dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); - count += s->dofs_size / s->dofs_entsize; - } - - dep->de_strlen = strtabsz; - dep->de_nrel = count; - dep->de_nsym = count + 1; /* the first symbol is always null */ - - if (dtp->dt_lazyload) { - dep->de_strlen += sizeof(DOFLAZYSTR); - dep->de_nsym++; - } else { - dep->de_strlen += sizeof(DOFSTR); - dep->de_nsym++; - } - - if ((dep->de_rel = calloc(dep->de_nrel, - sizeof(dep->de_rel[0]))) == NULL) { - return dt_set_errno(dtp, EDT_NOMEM); - } - - if ((dep->de_sym = calloc(dep->de_nsym, sizeof(Elf32_Sym))) == NULL) { - free(dep->de_rel); - return dt_set_errno(dtp, EDT_NOMEM); - } - - if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { - free(dep->de_rel); - free(dep->de_sym); - return dt_set_errno(dtp, EDT_NOMEM); - } - - count = 0; - strtabsz = 1; - dep->de_strtab[0] = '\0'; - rel = dep->de_rel; - sym = dep->de_sym; - dep->de_global = 1; - - /* - * The first symbol table entry must be zeroed and is always ignored. - */ - memset(sym, 0, sizeof(Elf32_Sym)); - sym++; - - /* - * Take a second pass through the DOF sections filling in the - * memory we allocated. - */ - for (i = 0; i < dof->dofh_secnum; i++) { - if (dofs[i].dofs_type != DOF_SECT_URELHDR) - continue; - - /*LINTED*/ - dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); - - s = &dofs[dofrh->dofr_strtab]; - strtab = (char *)dof + s->dofs_offset; - memcpy(dep->de_strtab + strtabsz, strtab + 1, s->dofs_size); - base = strtabsz; - strtabsz += s->dofs_size - 1; - - s = &dofs[dofrh->dofr_relsec]; - /*LINTED*/ - dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); - nrel = s->dofs_size / s->dofs_entsize; - - s = &dofs[dofrh->dofr_tgtsec]; - - for (j = 0; j < nrel; j++) { -#if defined(__i386) || defined(__amd64) - rel->r_offset = s->dofs_offset + - dofr[j].dofr_offset; - rel->r_info = ELF32_R_INFO(count + dep->de_global, - R_386_32); -#elif defined(__sparc) - /* - * Add 4 bytes to hit the low half of this 64-bit - * big-endian address. - */ - rel->r_offset = s->dofs_offset + - dofr[j].dofr_offset + 4; - rel->r_info = ELF32_R_INFO(count + dep->de_global, - R_SPARC_32); -#elif defined(__aarch64__) - rel->r_offset = s->dofs_offset + - dofr[j].dofr_offset; - rel->r_info = ELF32_R_INFO(count + dep->de_global, - R_ARM_ABS32); -#else -#error unknown ISA -#endif - - sym->st_name = base + dofr[j].dofr_name - 1; - sym->st_value = 0; - sym->st_size = 0; - sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC); - sym->st_other = 0; - sym->st_shndx = SHN_UNDEF; - - rel++; - sym++; - count++; - } - } - - /* - * Add a symbol for the DOF itself. We use a different symbol for - * lazily and actively loaded DOF to make them easy to distinguish. - */ - sym->st_name = strtabsz; - sym->st_value = 0; - sym->st_size = dof->dofh_filesz; - sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT); - sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN); - sym->st_shndx = ESHDR_DOF; - sym++; - - if (dtp->dt_lazyload) { - memcpy(dep->de_strtab + strtabsz, DOFLAZYSTR, - sizeof(DOFLAZYSTR)); - strtabsz += sizeof(DOFLAZYSTR); - } else { - memcpy(dep->de_strtab + strtabsz, DOFSTR, sizeof(DOFSTR)); - strtabsz += sizeof(DOFSTR); - } - - assert(count == dep->de_nrel); - assert(strtabsz == dep->de_strlen); - - return 0; -} - - -typedef struct dof_elf64 { - uint32_t de_nrel; - Elf64_Rela *de_rel; - uint32_t de_nsym; - Elf64_Sym *de_sym; - - uint32_t de_strlen; - char *de_strtab; - - uint32_t de_global; -} dof_elf64_t; - -static int -prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) -{ - dof_sec_t *dofs, *s; - dof_relohdr_t *dofrh; - dof_relodesc_t *dofr; - char *strtab; - int i, j, nrel; - size_t strtabsz = 1; - uint32_t count = 0; - size_t base; - Elf64_Sym *sym; - Elf64_Rela *rel; - - /*LINTED*/ - dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); - - /* - * First compute the size of the string table and the number of - * relocations present in the DOF. - */ - for (i = 0; i < dof->dofh_secnum; i++) { - if (dofs[i].dofs_type != DOF_SECT_URELHDR) - continue; - - /*LINTED*/ - dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); - - s = &dofs[dofrh->dofr_strtab]; - strtab = (char *)dof + s->dofs_offset; - assert(strtab[0] == '\0'); - strtabsz += s->dofs_size - 1; - - s = &dofs[dofrh->dofr_relsec]; - /*LINTED*/ - dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); - count += s->dofs_size / s->dofs_entsize; - } - - dep->de_strlen = strtabsz; - dep->de_nrel = count; - dep->de_nsym = count + 1; /* the first symbol is always null */ - - if (dtp->dt_lazyload) { - dep->de_strlen += sizeof(DOFLAZYSTR); - dep->de_nsym++; - } else { - dep->de_strlen += sizeof(DOFSTR); - dep->de_nsym++; - } - - if ((dep->de_rel = calloc(dep->de_nrel, - sizeof(dep->de_rel[0]))) == NULL) { - return dt_set_errno(dtp, EDT_NOMEM); - } - - if ((dep->de_sym = calloc(dep->de_nsym, sizeof(Elf64_Sym))) == NULL) { - free(dep->de_rel); - return dt_set_errno(dtp, EDT_NOMEM); - } - - if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { - free(dep->de_rel); - free(dep->de_sym); - return dt_set_errno(dtp, EDT_NOMEM); - } - - count = 0; - strtabsz = 1; - dep->de_strtab[0] = '\0'; - rel = dep->de_rel; - sym = dep->de_sym; - dep->de_global = 1; - - /* - * The first symbol table entry must be zeroed and is always ignored. - */ - memset(sym, 0, sizeof(Elf64_Sym)); - sym++; - - /* - * Take a second pass through the DOF sections filling in the - * memory we allocated. - */ - for (i = 0; i < dof->dofh_secnum; i++) { - if (dofs[i].dofs_type != DOF_SECT_URELHDR) - continue; - - /*LINTED*/ - dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); - - s = &dofs[dofrh->dofr_strtab]; - strtab = (char *)dof + s->dofs_offset; - memcpy(dep->de_strtab + strtabsz, strtab + 1, s->dofs_size); - base = strtabsz; - strtabsz += s->dofs_size - 1; - - s = &dofs[dofrh->dofr_relsec]; - /*LINTED*/ - dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); - nrel = s->dofs_size / s->dofs_entsize; - - s = &dofs[dofrh->dofr_tgtsec]; - - for (j = 0; j < nrel; j++) { -#if defined(__i386) || defined(__amd64) - rel->r_offset = s->dofs_offset + - dofr[j].dofr_offset; - rel->r_info = ELF64_R_INFO(count + dep->de_global, - R_X86_64_GLOB_DAT); -#elif defined(__sparc) - rel->r_offset = s->dofs_offset + - dofr[j].dofr_offset; - rel->r_info = ELF64_R_INFO(count + dep->de_global, - R_SPARC_64); -#elif defined(__aarch64__) - rel->r_offset = s->dofs_offset + - dofr[j].dofr_offset; - rel->r_info = ELF64_R_INFO(count + dep->de_global, - R_AARCH64_ABS64); -#else -#error unknown ISA -#endif - - sym->st_name = base + dofr[j].dofr_name - 1; - sym->st_value = 0; - sym->st_size = 0; - sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); - sym->st_other = 0; - sym->st_shndx = SHN_UNDEF; - - rel++; - sym++; - count++; - } - } - - /* - * Add a symbol for the DOF itself. We use a different symbol for - * lazily and actively loaded DOF to make them easy to distinguish. - */ - sym->st_name = strtabsz; - sym->st_value = 0; - sym->st_size = dof->dofh_filesz; - sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT); - sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN); - sym->st_shndx = ESHDR_DOF; - sym++; - - if (dtp->dt_lazyload) { - memcpy(dep->de_strtab + strtabsz, DOFLAZYSTR, - sizeof(DOFLAZYSTR)); - strtabsz += sizeof(DOFLAZYSTR); - } else { - memcpy(dep->de_strtab + strtabsz, DOFSTR, sizeof(DOFSTR)); - strtabsz += sizeof(DOFSTR); - } - - assert(count == dep->de_nrel); - assert(strtabsz == dep->de_strlen); - - return 0; -} - -/* - * Write out an ELF32 file prologue consisting of a header, section headers, - * and a section header string table. The DOF data will follow this prologue - * and complete the contents of the given ELF file. - */ +_dt_printflike_(4,5) static int -dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) +dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, const char *format, ...) { - struct { - Elf32_Ehdr ehdr; - Elf32_Shdr shdr[ESHDR_NUM]; - } elf_file; - - Elf32_Shdr *shp; - Elf32_Off off; - dof_elf32_t de; - int ret = 0; - uint_t nshdr; - - de.de_sym = NULL; /* gcc -Wmaybe-uninitialized */ - if (prepare_elf32(dtp, dof, &de) != 0) - return -1; /* errno is set for us */ - - /* - * If there are no relocations, we only need enough sections for - * the shstrtab and the DOF. - */ - nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; - - memset(&elf_file, 0, sizeof(elf_file)); - - elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; - elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; - elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; - elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; - elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; - elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32; -#if defined(_BIG_ENDIAN) - elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; -#elif defined(_LITTLE_ENDIAN) - elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; -#endif - elf_file.ehdr.e_type = ET_REL; -#if defined(__sparc) - elf_file.ehdr.e_machine = EM_SPARC; -#elif defined(__i386) || defined(__amd64) - elf_file.ehdr.e_machine = EM_386; -#endif - elf_file.ehdr.e_version = EV_CURRENT; - elf_file.ehdr.e_shoff = sizeof(Elf32_Ehdr); - elf_file.ehdr.e_ehsize = sizeof(Elf32_Ehdr); - elf_file.ehdr.e_phentsize = sizeof(Elf32_Phdr); - elf_file.ehdr.e_shentsize = sizeof(Elf32_Shdr); - elf_file.ehdr.e_shnum = nshdr; - elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; - off = sizeof(elf_file) + nshdr * sizeof(Elf32_Shdr); - - shp = &elf_file.shdr[ESHDR_SHSTRTAB]; - shp->sh_name = NAMEOFF_SHSTRTAB; - shp->sh_type = SHT_STRTAB; - shp->sh_offset = off; - shp->sh_size = sizeof(DTRACE_SHSTRTAB32); - shp->sh_addralign = sizeof(char); - off = shp->sh_offset + shp->sh_size; - - shp = &elf_file.shdr[ESHDR_STACKNOTE]; - shp->sh_name = NAMEOFF_STACKNOTE; - shp->sh_type = SHT_PROGBITS; - shp->sh_offset = off; - shp->sh_size = 0; - shp->sh_addralign = sizeof(char); - off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); - - shp = &elf_file.shdr[ESHDR_DOF]; - shp->sh_name = NAMEOFF_DOF; - shp->sh_flags = SHF_ALLOC; - shp->sh_type = SHT_SUNW_dof; - shp->sh_offset = off; - shp->sh_size = dof->dofh_filesz; - shp->sh_addralign = 8; - off = shp->sh_offset + shp->sh_size; - - shp = &elf_file.shdr[ESHDR_STRTAB]; - shp->sh_name = NAMEOFF_STRTAB; - shp->sh_flags = SHF_ALLOC; - shp->sh_type = SHT_STRTAB; - shp->sh_offset = off; - shp->sh_size = de.de_strlen; - shp->sh_addralign = sizeof(char); - off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); - - shp = &elf_file.shdr[ESHDR_SYMTAB]; - shp->sh_name = NAMEOFF_SYMTAB; - shp->sh_flags = SHF_ALLOC; - shp->sh_type = SHT_SYMTAB; - shp->sh_entsize = sizeof(Elf32_Sym); - shp->sh_link = ESHDR_STRTAB; - shp->sh_offset = off; - shp->sh_info = de.de_global; - shp->sh_size = de.de_nsym * sizeof(Elf32_Sym); - shp->sh_addralign = 4; - off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); - - if (de.de_nrel == 0) { - if (dt_write(dtp, fd, &elf_file, - sizeof(elf_file)) != sizeof(elf_file) || - PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || - PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || - PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || - PWRITE_SCN(ESHDR_DOF, dof)) { - ret = dt_set_errno(dtp, errno); - } - } else { - shp = &elf_file.shdr[ESHDR_REL]; - shp->sh_name = NAMEOFF_REL; - shp->sh_flags = SHF_ALLOC; -#ifdef __sparc - shp->sh_type = SHT_RELA; -#else - shp->sh_type = SHT_REL; -#endif - shp->sh_entsize = sizeof(de.de_rel[0]); - shp->sh_link = ESHDR_SYMTAB; - shp->sh_info = ESHDR_DOF; - shp->sh_offset = off; - shp->sh_size = de.de_nrel * sizeof(de.de_rel[0]); - shp->sh_addralign = 4; - - if (dt_write(dtp, fd, &elf_file, - sizeof(elf_file)) != sizeof(elf_file) || - PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || - PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || - PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || - PWRITE_SCN(ESHDR_REL, de.de_rel) || - PWRITE_SCN(ESHDR_DOF, dof)) { - ret = dt_set_errno(dtp, errno); - } - } - - free(de.de_strtab); - free(de.de_sym); - free(de.de_rel); - - return ret; -} - -/* - * Write out an ELF64 file prologue consisting of a header, section headers, - * and a section header string table. The DOF data will follow this prologue - * and complete the contents of the given ELF file. - */ -static int -dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) -{ - struct { - Elf64_Ehdr ehdr; - Elf64_Shdr shdr[ESHDR_NUM]; - } elf_file; - - Elf64_Shdr *shp; - Elf64_Off off; - dof_elf64_t de; - int ret = 0; - uint_t nshdr; + va_list ap; - de.de_sym = NULL; /* gcc -Wmaybe-uninitialized */ - if (prepare_elf64(dtp, dof, &de) != 0) - return -1; /* errno is set for us */ + va_start(ap, format); + dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); + va_end(ap); - /* - * If there are no relocations, we only need enough sections for - * the shstrtab and the DOF. - */ - nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; - - memset(&elf_file, 0, sizeof(elf_file)); - - elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; - elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; - elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; - elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; - elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; - elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64; -#if defined(_BIG_ENDIAN) - elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; -#elif defined(_LITTLE_ENDIAN) - elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; -#endif - elf_file.ehdr.e_type = ET_REL; -#if defined(__sparc) - elf_file.ehdr.e_machine = EM_SPARCV9; -#elif defined(__i386) || defined(__amd64) - elf_file.ehdr.e_machine = EM_X86_64; -#elif defined(__aarch64__) - elf_file.ehdr.e_machine = EM_AARCH64; -#endif - elf_file.ehdr.e_version = EV_CURRENT; - elf_file.ehdr.e_shoff = sizeof(Elf64_Ehdr); - elf_file.ehdr.e_ehsize = sizeof(Elf64_Ehdr); - elf_file.ehdr.e_phentsize = sizeof(Elf64_Phdr); - elf_file.ehdr.e_shentsize = sizeof(Elf64_Shdr); - elf_file.ehdr.e_shnum = nshdr; - elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; - off = sizeof(elf_file) + nshdr * sizeof(Elf64_Shdr); - - shp = &elf_file.shdr[ESHDR_SHSTRTAB]; - shp->sh_name = NAMEOFF_SHSTRTAB; - shp->sh_type = SHT_STRTAB; - shp->sh_offset = off; - shp->sh_size = sizeof(DTRACE_SHSTRTAB64); - shp->sh_addralign = sizeof(char); - off = shp->sh_offset + shp->sh_size; - - shp = &elf_file.shdr[ESHDR_STACKNOTE]; - shp->sh_name = NAMEOFF_STACKNOTE; - shp->sh_type = SHT_PROGBITS; - shp->sh_offset = off; - shp->sh_size = 0; - shp->sh_addralign = sizeof(char); - off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); - - shp = &elf_file.shdr[ESHDR_DOF]; - shp->sh_name = NAMEOFF_DOF; - shp->sh_flags = SHF_ALLOC; - shp->sh_type = SHT_SUNW_dof; - shp->sh_offset = off; - shp->sh_size = dof->dofh_filesz; - shp->sh_addralign = 8; - off = shp->sh_offset + shp->sh_size; - - shp = &elf_file.shdr[ESHDR_STRTAB]; - shp->sh_name = NAMEOFF_STRTAB; - shp->sh_flags = SHF_ALLOC; - shp->sh_type = SHT_STRTAB; - shp->sh_offset = off; - shp->sh_size = de.de_strlen; - shp->sh_addralign = sizeof(char); - off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); - - shp = &elf_file.shdr[ESHDR_SYMTAB]; - shp->sh_name = NAMEOFF_SYMTAB; - shp->sh_flags = SHF_ALLOC; - shp->sh_type = SHT_SYMTAB; - shp->sh_entsize = sizeof(Elf64_Sym); - shp->sh_link = ESHDR_STRTAB; - shp->sh_offset = off; - shp->sh_info = de.de_global; - shp->sh_size = de.de_nsym * sizeof(Elf64_Sym); - shp->sh_addralign = 8; - off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); - - if (de.de_nrel == 0) { - if (dt_write(dtp, fd, &elf_file, - sizeof(elf_file)) != sizeof(elf_file) || - PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || - PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || - PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || - PWRITE_SCN(ESHDR_DOF, dof)) { - ret = dt_set_errno(dtp, errno); - } - } else { - shp = &elf_file.shdr[ESHDR_REL]; - shp->sh_name = NAMEOFF_REL; - shp->sh_flags = SHF_ALLOC; - shp->sh_type = SHT_RELA; - shp->sh_entsize = sizeof(de.de_rel[0]); - shp->sh_link = ESHDR_SYMTAB; - shp->sh_info = ESHDR_DOF; - shp->sh_offset = off; - shp->sh_size = de.de_nrel * sizeof(de.de_rel[0]); - shp->sh_addralign = 8; - - if (dt_write(dtp, fd, &elf_file, - sizeof(elf_file)) != sizeof(elf_file) || - PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || - PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || - PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || - PWRITE_SCN(ESHDR_REL, de.de_rel) || - PWRITE_SCN(ESHDR_DOF, dof)) { - ret = dt_set_errno(dtp, errno); - } - } + if (elf != NULL) + elf_end(elf); - free(de.de_strtab); - free(de.de_sym); - free(de.de_rel); + if (fd >= 0) + close(fd); - return ret; + return dt_set_errno(dtp, EDT_COMPILER); } -static int -dt_elf_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn, - GElf_Sym *sym) +typedef struct usdt_note usdt_note_t; +struct usdt_note { + usdt_note_t *next; + char *data; + size_t size; +}; + +typedef struct usdt_elf { + dtrace_hdl_t *dtp; + Elf_Scn *note; + off_t base; + off_t size; + usdt_note_t notes; +} usdt_elf_t; + +#define STORE_ATTR(n, d, c) (((n) << 24) | ((d) << 16) | ((c) << 8)) + +static void +note_store_attr(char **p, const dtrace_attribute_t *ap) { - int i, ret = -1; - GElf_Sym s; - - for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) { - if (GELF_ST_TYPE(sym->st_info) == STT_FUNC && - shn == sym->st_shndx && - sym->st_value <= addr && - addr < sym->st_value + sym->st_size) { - if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) - return 0; - - ret = 0; - s = *sym; - } - } + uint32_t *attr = (uint32_t *)*p; - if (ret == 0) - *sym = s; - return ret; + *attr = STORE_ATTR(ap->dtat_name, ap->dtat_data, ap->dtat_class); + *p += sizeof(uint32_t); } -#if defined(__sparc) - -#define DT_OP_RET 0x81c7e008 -#define DT_OP_NOP 0x01000000 -#define DT_OP_CALL 0x40000000 -#define DT_OP_CLR_O0 0x90102000 - -#define DT_IS_MOV_O7(inst) (((inst) & 0xffffe000) == 0x9e100000) -#define DT_IS_RESTORE(inst) (((inst) & 0xc1f80000) == 0x81e80000) -#define DT_IS_RETL(inst) (((inst) & 0xfff83fff) == 0x81c02008) - -#define DT_RS2(inst) ((inst) & 0x1f) -#define DT_MAKE_RETL(reg) (0x81c02008 | ((reg) << 14)) - -/*ARGSUSED*/ static int -dt_modtext(dtrace_hdl_t *dtp, char *p, GElf_Rela *rela, uint32_t *off) +note_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) { - uint32_t *ip; - - if ((rela->r_offset & (sizeof(uint32_t) - 1)) != 0) - return -1; - - /*LINTED*/ - ip = (uint32_t *)(p + rela->r_offset); - - /* - * We only know about some specific relocation types. - * We also recognize relocation type NONE, since that gets used for - * relocations of USDT probes, and we might be re-processing a file. - */ - if (GELF_R_TYPE(rela->r_info) != R_SPARC_WDISP30 && - GELF_R_TYPE(rela->r_info) != R_SPARC_WPLT30 && - GELF_R_TYPE(rela->r_info) != R_386_NONE) - return -1; - - /* - * We may have already processed this object file in an earlier linker - * invocation. Check to see if the present instruction sequence matches - * the one we would install below. - */ - if (DT_IS_RESTORE(ip[1])) { - if (ip[0] == DT_OP_RET) { - (*off) += sizeof(ip[0]); - return 0; - } - } else if (DT_IS_MOV_O7(ip[1])) { - if (DT_IS_RETL(ip[0])) - return 0; - } else { - if (ip[0] == DT_OP_NOP) { - (*off) += sizeof(ip[0]); - return 0; - } - } - - /* - * We only expect call instructions with a displacement of 0. - */ - if (ip[0] != DT_OP_CALL) { - dt_dprintf("found %x instead of a call instruction at %llx\n", - ip[0], (unsigned long long)rela->r_offset); - return -1; - } - - /* - * If the call is followed by a restore, it's a tail call so - * change the call to a ret. If the call if followed by a mov - * of a register into %o7, it's a tail call in leaf context - * so change the call to a retl-like instruction that returns - * to that register value + 8 (rather than the typical %o7 + - * 8); the delay slot instruction is left, but should have no - * effect. Otherwise we change the call to be a nop. We - * identify the subsequent instruction as the probe point in - * all but the leaf tail-call case to ensure that arguments to - * the probe are complete and consistent. An astute, though - * largely hypothetical, observer would note that there is the - * possibility of a false-positive probe firing if the function - * contained a branch to the instruction in the delay slot of - * the call. Fixing this would require significant in-kernel - * modifications, and isn't worth doing until we see it in the - * wild. - */ - if (DT_IS_RESTORE(ip[1])) { - ip[0] = DT_OP_RET; - (*off) += sizeof(ip[0]); - } else if (DT_IS_MOV_O7(ip[1])) { - ip[0] = DT_MAKE_RETL(DT_RS2(ip[1])); - } else { - ip[0] = DT_OP_NOP; - (*off) += sizeof(ip[0]); - } + usdt_elf_t *usdt = data; + usdt_note_t *note; + dt_node_t *dnp; + dt_probe_t *prp = idp->di_data; + char *buf, *p; + size_t len, sz; + int i; + char n[DT_TYPE_NAMELEN]; + + len = strlen(prp->pr_name); + sz = ALIGN(len + 1, 4) + 2 * sizeof(uint8_t) + + (prp->nargc + prp->xargc) * DT_TYPE_NAMELEN + + prp->xargc * sizeof(uint8_t); + sz = ALIGN(sz, 4); + + buf = malloc(sz); + if (buf == NULL) + return dt_set_errno(usdt->dtp, EDT_NOMEM); + memset(buf, 0, sz); + + p = buf; + strcpy(p, prp->pr_name); + p += len + 1; + *(uint8_t *)p = prp->nargc; + p++; + for (dnp = prp->nargs; dnp != NULL; dnp = dnp->dn_list) { + strcpy(p, ctf_type_name(dnp->dn_ctfp, dnp->dn_type, n, sizeof(n))); + p += strlen(p) + 1; + } + *(uint8_t *)p = prp->xargc; + p++; + for (dnp = prp->xargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) { + strcpy(p, ctf_type_name(dnp->dn_ctfp, dnp->dn_type, n, sizeof(n))); + p += strlen(p) + 1; + *p++ = prp->mapping[i]; + } + + sz = p - buf; + + note = dt_zalloc(usdt->dtp, sizeof(usdt_note_t)); + note->data = buf; + note->size = ALIGN(sz, 4); + note->next = usdt->notes.next; + usdt->notes.next = note; return 0; } -#elif defined(__i386) || defined(__amd64) - -#define DT_OP_NOP 0x90 -#define DT_OP_RET 0xc3 -#define DT_OP_CALL 0xe8 -#define DT_OP_JMP32 0xe9 - static int -dt_modtext(dtrace_hdl_t *dtp, char *p, GElf_Rela *rela, uint32_t *off) +note_add_provider(usdt_elf_t *usdt, dt_provider_t *pvp) { - uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1); - uint8_t ret; + usdt_note_t *note; + Elf_Data *dbuf; + char *buf, *p; + size_t len, sz; + uint32_t nprobes = dt_idhash_size(pvp->pv_probes); - /* - * On x86, the first byte of the instruction is the call opcode and - * the next four bytes are the 32-bit address; the relocation is for - * the address operand. We back up the offset to the first byte of - * the instruction. For is-enabled probes, we later advance the offset - * so that it hits the first nop in the instruction sequence. - */ - (*off) -= 1; +#define PROV_NOTE_HEADSZ \ + ((3 * sizeof(uint32_t)) + /* namesz, descsz, type */ \ + ALIGN(strlen(_USDT_PV_NOTE_NAME) + 1, 4)) /* "prov\0" */ - /* - * We only know about some specific relocation types. Luckily these - * types have the same values on both 32-bit and 64-bit x86 - * architectures. - * We also recognize relocation type NONE, since that gets used for - * relocations of USDT probes, and we might be re-processing a file. - */ - if (GELF_R_TYPE(rela->r_info) != R_386_PC32 && - GELF_R_TYPE(rela->r_info) != R_386_PLT32 && - GELF_R_TYPE(rela->r_info) != R_386_NONE) { - dt_dprintf("unexpected reloc type %li\n", GELF_R_TYPE(rela->r_info)); - return -1; - } - - /* - * We may have already processed this object file in an earlier linker - * invocation. Check to see if the present instruction sequence matches - * the one we would install. - */ - if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) && - ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP && - ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) + if (!nprobes) return 0; - /* - * We expect either a call instrution with a 32-bit displacement or a - * jmp instruction with a 32-bit displacement acting as a tail-call. - */ - if (ip[0] != DT_OP_CALL && ip[0] != DT_OP_JMP32) { - dt_dprintf("found %x instead of a call or jmp instruction at " - "%llx\n", ip[0], (unsigned long long)rela->r_offset); - return -1; - } - - ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : DT_OP_NOP; - - /* - * Establish the instruction sequence: all nops. - */ - ip[0] = ret; - ip[1] = DT_OP_NOP; - ip[2] = DT_OP_NOP; - ip[3] = DT_OP_NOP; - ip[4] = DT_OP_NOP; + /* Ensure the note starts on a 4-byte alignment boundary. */ + usdt->base = ALIGN(usdt->base + usdt->size, 4); + usdt->size = 0; + + len = strlen(pvp->desc.dtvd_name); + sz = PROV_NOTE_HEADSZ + + ALIGN(len + 1, 4) + /* provider name */ + 6 * sizeof(uint32_t); /* stability attributes */ + + buf = malloc(sz); + if (buf == NULL) + return dt_set_errno(usdt->dtp, EDT_NOMEM); + memset(buf, 0, sz); + + /* Add the note header. */ + dbuf = elf_newdata(usdt->note); + dbuf->d_align = sizeof(uint32_t); + dbuf->d_off = usdt->base; + dbuf->d_buf = buf; + dbuf->d_size = sz; + usdt->size = sz; + + p = buf + PROV_NOTE_HEADSZ; + strcpy(p, pvp->desc.dtvd_name); + p += ALIGN(len + 1, 4); + note_store_attr(&p, &pvp->desc.dtvd_attr.dtpa_provider); + note_store_attr(&p, &pvp->desc.dtvd_attr.dtpa_mod); + note_store_attr(&p, &pvp->desc.dtvd_attr.dtpa_func); + note_store_attr(&p, &pvp->desc.dtvd_attr.dtpa_name); + note_store_attr(&p, &pvp->desc.dtvd_attr.dtpa_args); + *(uint32_t *)p = nprobes; + p += sizeof(uint32_t); + + /* Add the probe definitions. */ + dt_idhash_iter(pvp->pv_probes, note_add_probe, usdt); + + /* Add the note fragments. */ + note = usdt->notes.next; + while (note) { + usdt_note_t *next = note->next; + + dbuf = elf_newdata(usdt->note); + dbuf->d_align = sizeof(char); + dbuf->d_off = usdt->base + usdt->size; + dbuf->d_buf = note->data; + dbuf->d_size = note->size; + usdt->size += note->size; + + dt_free(usdt->dtp, note); + note = next; + } + + /* Construct the note header. */ + *((uint32_t *)&buf[0]) = 5; + *((uint32_t *)&buf[4]) = usdt->size - PROV_NOTE_HEADSZ; + *((uint32_t *)&buf[8]) = 1; + memcpy(&buf[12], _USDT_PV_NOTE_NAME, 4); + + usdt->notes.next = NULL; return 0; } -#elif defined(__aarch64__) - -#define DT_OP_NOP 0xd503201f -#define DT_OP_RET 0xd65f03c0 -#define DT_OP_CALL26 0x94000000 -#define DT_OP_JUMP26 0x14000000 - static int -dt_modtext(dtrace_hdl_t *dtp, char *p, GElf_Rela *rela, uint32_t *off) +note_add_version(usdt_elf_t *usdt) { - uint32_t *ip; - - /* - * Ensure that the offset is aligned on an instruction boundary. - */ - if ((rela->r_offset & (sizeof(uint32_t) - 1)) != 0) - return -1; - - /* - * We only know about some specific relocation types. - * We also recognize relocation type NONE, since that gets used for - * relocations of USDT probes, and we might be re-processing a file. - */ - if (GELF_R_TYPE(rela->r_info) != R_AARCH64_CALL26 && - GELF_R_TYPE(rela->r_info) != R_AARCH64_JUMP26 && - GELF_R_TYPE(rela->r_info) != R_AARCH64_NONE) - return -1; - - ip = (uint32_t *)(p + rela->r_offset); - - /* - * We may have already processed this object file in an earlier linker - * invocation. Check to see if the present instruction sequence matches - * the one we would install below. - */ - if (ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) - return 0; - - /* - * We only expect call instructions with a displacement of 0, or a jump - * instruction acting as a tail call. - */ - if (ip[0] != DT_OP_CALL26 && ip[0] != DT_OP_JUMP26) { - dt_dprintf("found %x instead of a call or jmp instruction at " - "%llx\n", ip[0], (unsigned long long)rela->r_offset); - return -1; - } - - /* - * On arm64, we encode all probes as a regular branch for non-tail call - * locations, and a jump for tail call locations. Calls are to be - * converted into a no-op whereas jumps should become a return. - */ - if (ip[0] == DT_OP_CALL26) - ip[0] = DT_OP_NOP; - else - ip[0] = DT_OP_RET; + Elf_Data *dbuf; + char *buf, *p; + size_t len, sz; + +#define DVER_NOTE_HEADSZ \ + ((3 * sizeof(uint32_t)) + /* namesz, descsz, type */ \ + ALIGN(5, 4)) /* "dver\0" */ + + /* Ensure the note starts on a 4-byte alignment boundary. */ + usdt->base = ALIGN(usdt->base + usdt->size, 4); + usdt->size = 0; + + len = strlen(_dtrace_version); + sz = DVER_NOTE_HEADSZ + ALIGN(len + 1, 4); + + buf = malloc(sz); + if (buf == NULL) + return dt_set_errno(usdt->dtp, EDT_NOMEM); + memset(buf, 0, sz); + + /* Construct the note header. */ + *((uint32_t *)&buf[0]) = 5; + *((uint32_t *)&buf[4]) = sz - DVER_NOTE_HEADSZ; + *((uint32_t *)&buf[8]) = 1; + memcpy(&buf[12], "dver", 4); + + /* Add the data. */ + p = buf + DVER_NOTE_HEADSZ; + strcpy(p, _dtrace_version); + + /* Add the note header. */ + dbuf = elf_newdata(usdt->note); + dbuf->d_align = sizeof(uint32_t); + dbuf->d_off = usdt->base; + dbuf->d_buf = buf; + dbuf->d_size = sz; + usdt->size = sz; + + usdt->notes.next = NULL; return 0; } -#else -#error unknown ISA -#endif -/*PRINTFLIKE5*/ -_dt_printflike_(5,6) static int -dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs, - const char *format, ...) +note_add_utsname(usdt_elf_t *usdt) { - va_list ap; - dt_link_pair_t *pair; + Elf_Data *dbuf; + char *buf, *p; + size_t len, sz; + +#define UTSN_NOTE_HEADSZ \ + ((3 * sizeof(uint32_t)) + /* namesz, descsz, type */ \ + ALIGN(5, 4)) /* "utsn\0" */ + + /* Ensure the note starts on a 4-byte alignment boundary. */ + usdt->base = ALIGN(usdt->base + usdt->size, 4); + usdt->size = 0; + + len = sizeof(struct utsname); + sz = UTSN_NOTE_HEADSZ + ALIGN(len, 4); + + buf = malloc(sz); + if (buf == NULL) + return dt_set_errno(usdt->dtp, EDT_NOMEM); + memset(buf, 0, sz); + + /* Construct the note header. */ + *((uint32_t *)&buf[0]) = 5; + *((uint32_t *)&buf[4]) = sz - UTSN_NOTE_HEADSZ; + *((uint32_t *)&buf[8]) = 1; + memcpy(&buf[12], "utsn", 4); + + /* Add the data. */ + p = buf + UTSN_NOTE_HEADSZ; + memcpy(p, &usdt->dtp->dt_uts, sizeof(struct utsname)); + + /* Add the note header. */ + dbuf = elf_newdata(usdt->note); + dbuf->d_align = sizeof(uint32_t); + dbuf->d_off = usdt->base; + dbuf->d_buf = buf; + dbuf->d_size = sz; + usdt->size = sz; + + usdt->notes.next = NULL; - va_start(ap, format); - dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); - va_end(ap); - - if (elf != NULL) - elf_end(elf); - - if (fd >= 0) - close(fd); - - while ((pair = bufs) != NULL) { - bufs = pair->dlp_next; - dt_free(dtp, pair->dlp_str); - dt_free(dtp, pair->dlp_sym); - dt_free(dtp, pair); - } - - return dt_set_errno(dtp, EDT_COMPILER); + return 0; } static int -process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp) +create_elf64(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, int fd, uint_t flags) { - static const char dt_prefix[] = "__dtrace"; - static const char dt_enabled[] = "enabled"; - static const char dt_symprefix[] = "$dtrace"; - static const char dt_symfmt[] = "%s%d.%s"; - int fd, i, ndx, eprobe, mod = 0; - Elf *elf = NULL; - GElf_Ehdr ehdr; - Elf_Scn *scn_rel, *scn_sym, *scn_str, *scn_tgt; - Elf_Data *data_rel, *data_sym, *data_str, *data_tgt; - GElf_Shdr shdr_rel, shdr_sym, shdr_str, shdr_tgt; - GElf_Sym rsym, fsym, dsym; - GElf_Rela rela; - char *s, *p, *r; - char pname[DTRACE_PROVNAMELEN]; - dt_provider_t *pvp; - dt_probe_t *prp; - uint32_t off, eclass, emachine1, emachine2; - size_t symsize, nsym, isym, istr, len; - key_t objkey; - dt_link_pair_t *pair, *bufs = NULL; - dt_strtab_t *strtab; - int flags = dtp->dt_link_no_mmap ? ELF_C_RDWR : ELF_C_RDWR_MMAP; - - if ((fd = open64(obj, O_RDWR)) == -1) { - return dt_link_error(dtp, elf, fd, bufs, - "failed to open %s: %s", obj, strerror(errno)); - } + usdt_elf_t *usdt; + Elf *elf; + Elf64_Ehdr *ehdr; + Elf64_Shdr *shdr; + Elf_Scn *scn; + Elf_Data *dbuf; + dt_htab_next_t *it = NULL; + dt_provider_t *pvp; + static const char SHSTRTAB[] = "\0" + ".shstrtab\0" /* 1 */ +#define SECT_SHSTRTAB 1 +#define NAMEOFF_SHSTRTAB 1 /* .shstrtab */ + ".note.GNU-stack\0" /* 11 */ +#define SECT_NOTE_GNUTACK 2 +#define NAMEOFF_NOTE_GNUSTACK 11 /* .note.GNU-stack */ + ".note.usdt\0"; /* 27 */ +#define SECT_NOTE_USDT 3 +#define NAMEOFF_NOTE_USDT 27 /* .note.usdt */ + + if (!(flags & DTRACE_D_PROBES)) + return 0; - if ((elf = elf_begin(fd, flags, NULL)) == NULL) { - return dt_link_error(dtp, elf, fd, bufs, - "failed to process %s: %s", obj, elf_errmsg(elf_errno())); + usdt = dt_zalloc(dtp, sizeof(usdt_elf_t)); + if (!usdt) { + dt_set_errno(dtp, EDT_NOMEM); + goto fail; } - switch (elf_kind(elf)) { - case ELF_K_ELF: - break; - case ELF_K_AR: - return dt_link_error(dtp, elf, fd, bufs, "archives are not " - "permitted; use the contents of the archive instead: %s", - obj); - default: - return dt_link_error(dtp, elf, fd, bufs, - "invalid file type: %s", obj); - } + usdt->dtp = dtp; + elf = elf_begin(fd, ELF_C_WRITE, NULL); + if (!elf) + goto fail; - if (gelf_getehdr(elf, &ehdr) == NULL) { - return dt_link_error(dtp, elf, fd, bufs, "corrupt file: %s", - obj); - } - - if (dtp->dt_oflags & DTRACE_O_ILP32) { - eclass = ELFCLASS32; -#if defined(__sparc) - emachine1 = EM_SPARC; - emachine2 = EM_SPARC32PLUS; -#elif defined(__i386) || defined(__amd64) - emachine1 = emachine2 = EM_386; -#endif - symsize = sizeof(Elf32_Sym); - } else { - eclass = ELFCLASS64; -#if defined(__sparc) - emachine1 = emachine2 = EM_SPARCV9; -#elif defined(__i386) || defined(__amd64) - emachine1 = emachine2 = EM_X86_64; + ehdr = elf64_newehdr(elf); + ehdr->e_type = ET_REL; +#if defined(__amd64) + ehdr->e_machine = EM_X86_64; #elif defined(__aarch64__) - emachine1 = emachine2 = EM_AARCH64; + ehdr->e_machine = EM_AARCH64; #endif - symsize = sizeof(Elf64_Sym); - } - - if (ehdr.e_ident[EI_CLASS] != eclass) - return dt_link_error(dtp, elf, fd, bufs, - "incorrect ELF class for object file: %s", obj); - - if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) - return dt_link_error(dtp, elf, fd, bufs, - "incorrect ELF machine type for object file: %s", obj); - - /* - * We use this token as a relatively unique handle for this file on the - * system in order to disambiguate potential conflicts between files of - * the same name which contain identially named local symbols. - */ - if ((objkey = ftok(obj, 0)) == (key_t)-1) - return dt_link_error(dtp, elf, fd, bufs, - "failed to generate unique key for object file: %s", obj); - - scn_rel = NULL; - while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { - if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) - goto err; - - /* - * Skip any non-relocation sections. - */ - if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) - continue; - - if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL) - goto err; - - /* - * Grab the section, section header and section data for the - * symbol table that this relocation section references. - */ - if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL || - gelf_getshdr(scn_sym, &shdr_sym) == NULL || - (data_sym = elf_getdata(scn_sym, NULL)) == NULL) - goto err; - - /* - * Ditto for that symbol table's string table. - */ - if ((scn_str = elf_getscn(elf, shdr_sym.sh_link)) == NULL || - gelf_getshdr(scn_str, &shdr_str) == NULL || - (data_str = elf_getdata(scn_str, NULL)) == NULL) - goto err; - - /* - * Grab the section, section header and section data for the - * target section for the relocations. For the relocations - * we're looking for -- this will typically be the text of the - * object file. - */ - if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL || - gelf_getshdr(scn_tgt, &shdr_tgt) == NULL || - (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL) - goto err; - - /* - * We're looking for relocations to symbols matching this form: - * - * __dtrace[enabled]____ - * - * For the generated object, we need to record the location - * identified by the relocation, and create a new relocation - * in the generated object that will be resolved at link time - * to the location of the function in which the probe is - * embedded. In the target object, we change the matched symbol - * so that it will be ignored at link time, and we modify the - * target (text) section to replace the call instruction with - * one or more nops. - * - * If the function containing the probe is locally scoped - * (static), we create an alias used by the relocation in the - * generated object. The alias, a new symbol, will be global - * (so that the relocation from the generated object can be - * resolved), and hidden (so that it is converted to a local - * symbol at link time). Such aliases have this form: - * - * $dtrace. - * - * We take a first pass through all the relocations to - * populate our string table and count the number of extra - * symbols we'll require. - */ - strtab = dt_strtab_create(BUFSIZ); - nsym = 0; - isym = data_sym->d_size / symsize; - istr = data_str->d_size; - - for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { - - if (shdr_rel.sh_type == SHT_RELA) { - if (gelf_getrela(data_rel, i, &rela) == NULL) - continue; - } else { - GElf_Rel rel; - if (gelf_getrel(data_rel, i, &rel) == NULL) - continue; - rela.r_offset = rel.r_offset; - rela.r_info = rel.r_info; - rela.r_addend = 0; - } - - if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info), - &rsym) == NULL) { - dt_strtab_destroy(strtab); - goto err; - } - - s = (char *)data_str->d_buf + rsym.st_name; - - if (strncmp(s, dt_prefix, sizeof(dt_prefix) - 1) != 0) - continue; - - if (dt_elf_symtab_lookup(data_sym, isym, rela.r_offset, - shdr_rel.sh_info, &fsym) != 0) { - dt_strtab_destroy(strtab); - goto err; - } - - if (GELF_ST_BIND(fsym.st_info) != STB_LOCAL) - continue; - - if (fsym.st_name > data_str->d_size) { - dt_strtab_destroy(strtab); - goto err; - } - - s = (char *)data_str->d_buf + fsym.st_name; - - /* - * If this symbol isn't of type function, we've really - * driven off the rails or the object file is corrupt. - */ - if (GELF_ST_TYPE(fsym.st_info) != STT_FUNC) { - dt_strtab_destroy(strtab); - return dt_link_error(dtp, elf, fd, bufs, - "expected %s to be of type function", s); - } - - len = snprintf(NULL, 0, dt_symfmt, dt_symprefix, - objkey, s) + 1; - if ((p = dt_alloc(dtp, len)) == NULL) { - dt_strtab_destroy(strtab); - goto err; - } - snprintf(p, len, dt_symfmt, dt_symprefix, objkey, s); - - if (dt_strtab_index(strtab, p) == -1) { - nsym++; - dt_strtab_insert(strtab, p); - } - - dt_free(dtp, p); - } - - /* - * If needed, allocate the additional space for the symbol - * table and string table copying the old data into the new - * buffers, and marking the buffers as dirty. We inject those - * newly allocated buffers into the libelf data structures, but - * are still responsible for freeing them once we're done with - * the elf handle. - */ - if (nsym > 0) { - /* - * The first byte of the string table is reserved - * for the \0 entry. - */ - len = dt_strtab_size(strtab) - 1; - - assert(len > 0); - assert(dt_strtab_index(strtab, "") == 0); - - dt_strtab_destroy(strtab); - - if ((pair = dt_alloc(dtp, sizeof(*pair))) == NULL) - goto err; - - if ((pair->dlp_str = dt_alloc(dtp, data_str->d_size + - len)) == NULL) { - dt_free(dtp, pair); - goto err; - } - - if ((pair->dlp_sym = dt_alloc(dtp, data_sym->d_size + - nsym * symsize)) == NULL) { - dt_free(dtp, pair->dlp_str); - dt_free(dtp, pair); - goto err; - } - - pair->dlp_next = bufs; - bufs = pair; - - memcpy(pair->dlp_str, data_str->d_buf, - data_str->d_size); - data_str->d_buf = pair->dlp_str; - data_str->d_size += len; - elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY); - - shdr_str.sh_size += len; - gelf_update_shdr(scn_str, &shdr_str); - - memcpy(pair->dlp_sym, data_sym->d_buf, - data_sym->d_size); - data_sym->d_buf = pair->dlp_sym; - data_sym->d_size += nsym * symsize; - elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY); - - shdr_sym.sh_size += nsym * symsize; - gelf_update_shdr(scn_sym, &shdr_sym); - - nsym += isym; - } else { - dt_strtab_destroy(strtab); - } - - /* - * Now that the tables have been allocated, perform the - * modifications described above. - */ - for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { - - if (shdr_rel.sh_type == SHT_RELA) { - if (gelf_getrela(data_rel, i, &rela) == NULL) - continue; - } else { - GElf_Rel rel; - if (gelf_getrel(data_rel, i, &rel) == NULL) - continue; - rela.r_offset = rel.r_offset; - rela.r_info = rel.r_info; - rela.r_addend = 0; - } - - ndx = GELF_R_SYM(rela.r_info); - - if (gelf_getsym(data_sym, ndx, &rsym) == NULL || - rsym.st_name > data_str->d_size) - goto err; - - s = (char *)data_str->d_buf + rsym.st_name; - - if (strncmp(s, dt_prefix, sizeof(dt_prefix) - 1) != 0) - continue; - - s += sizeof(dt_prefix) - 1; - - /* - * Check to see if this is an 'is-enabled' check as - * opposed to a normal probe. - */ - if (strncmp(s, dt_enabled, - sizeof(dt_enabled) - 1) == 0) { - s += sizeof(dt_enabled) - 1; - eprobe = 1; - *eprobesp = 1; - dt_dprintf("is-enabled probe\n"); - } else { - eprobe = 0; - dt_dprintf("normal probe\n"); - } - - if (*s++ != '_') - goto err; - - if ((p = strstr(s, "___")) == NULL || - p - s >= sizeof(pname)) - goto err; - - memcpy(pname, s, p - s); - pname[p - s] = '\0'; - - p = strhyphenate(p + 3); /* strlen("___") */ - - if (dt_elf_symtab_lookup(data_sym, isym, rela.r_offset, - shdr_rel.sh_info, &fsym) != 0) - goto err; - - if (fsym.st_name > data_str->d_size) - goto err; - - assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC); - - /* - * If a NULL relocation name is passed to - * dt_probe_define(), the function name is used for the - * relocation. The relocation needs to use a mangled - * name if the symbol is locally scoped; the function - * name may need to change if we've found the global - * alias for the locally scoped symbol (we prefer - * global symbols to locals in dt_elf_symtab_lookup()). - */ - s = (char *)data_str->d_buf + fsym.st_name; - r = NULL; - - if (GELF_ST_BIND(fsym.st_info) == STB_LOCAL) { - dsym = fsym; - dsym.st_name = istr; - dsym.st_info = GELF_ST_INFO(STB_GLOBAL, - STT_FUNC); - dsym.st_other = - ELF64_ST_VISIBILITY(STV_ELIMINATE); - gelf_update_sym(data_sym, isym, &dsym); - - r = (char *)data_str->d_buf + istr; - istr += 1 + sprintf(r, dt_symfmt, - dt_symprefix, objkey, s); - isym++; - assert(isym <= nsym); - - } else if (strncmp(s, dt_symprefix, - strlen(dt_symprefix)) == 0) { - r = s; - if ((s = strchr(s, '.')) == NULL) - goto err; - s++; - } - - if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) - return dt_link_error(dtp, elf, fd, bufs, - "no such provider %s", pname); - - if ((prp = dt_probe_lookup2(pvp, p)) == NULL) - return dt_link_error(dtp, elf, fd, bufs, - "no such probe %s", p); - - assert(fsym.st_value <= rela.r_offset); - - off = rela.r_offset - fsym.st_value; - if (dt_modtext(dtp, data_tgt->d_buf, &rela, &off) != 0) - goto err; - - if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) - return dt_link_error(dtp, elf, fd, bufs, - "failed to allocate space for probe"); - - /* - * This symbol may already have been marked to - * be ignored by another relocation referencing - * the same symbol or if this object file has - * already been processed by an earlier link - * invocation. - */ - if (rsym.st_shndx != SHN_SUNW_IGNORE) { - mod = 1; - elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY); - rsym.st_shndx = SHN_SUNW_IGNORE; - gelf_update_sym(data_sym, ndx, &rsym); - } - - /* - * This relocation is no longer needed. The linker on - * Linux doesn't know about SHN_SUNW_IGNORE, so we mark - * the relocation with type NONE. Failing to do so - * causes the linker to try to fill in an address on - * top of the NOPs we so carefully planted. - */ - if (rela.r_info != GELF_R_INFO(ndx,0)) { - mod = 1; - elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY); - if (shdr_rel.sh_type == SHT_RELA) { - rela.r_info = GELF_R_INFO(ndx, 0); - gelf_update_rela(data_rel, i, &rela); - } else { - GElf_Rel rel; - - rel.r_offset = rela.r_offset; - rel.r_info = GELF_R_INFO(ndx, 0); - gelf_update_rel(data_rel, i, &rel); - } - } - } - } + ehdr->e_version = EV_CURRENT; + ehdr->e_shoff = sizeof(Elf64_Ehdr); + ehdr->e_ehsize = sizeof(Elf64_Ehdr); + ehdr->e_phentsize = sizeof(Elf64_Phdr); + ehdr->e_shentsize = sizeof(Elf64_Shdr); + ehdr->e_shstrndx = 1; + + /* Create .shstrtab */ + scn = elf_newscn(elf); + shdr = elf64_getshdr(scn); + shdr->sh_name = NAMEOFF_SHSTRTAB; + shdr->sh_type = SHT_STRTAB; + shdr->sh_addralign = sizeof(char); + + dbuf = elf_newdata(scn); + dbuf->d_size = sizeof(SHSTRTAB); + dbuf->d_buf = malloc(dbuf->d_size); + if (!dbuf->d_buf) { + dt_set_errno(dtp, EDT_NOMEM); + goto fail; + } + memcpy(dbuf->d_buf, SHSTRTAB, dbuf->d_size); + + /* Create .note.GNU-stack */ + scn = elf_newscn(elf); + shdr = elf64_getshdr(scn); + shdr->sh_name = NAMEOFF_NOTE_GNUSTACK; + shdr->sh_type = SHT_PROGBITS; + shdr->sh_addralign = sizeof(char); + + dbuf = elf_newdata(scn); + + /* Create .note.usdt */ + usdt->note = elf_newscn(elf); + shdr = elf64_getshdr(usdt->note); + shdr->sh_name = NAMEOFF_NOTE_USDT; + shdr->sh_type = SHT_NOTE; + shdr->sh_addralign = sizeof(char); + + /* Add the provider definitions. */ + while ((pvp = dt_htab_next(dtp->dt_provs, &it)) != NULL) + note_add_provider(usdt, pvp); + + if (!(flags & DTRACE_D_STRIP)) { + note_add_version(usdt); + note_add_utsname(usdt); + } + + dt_free(dtp, usdt); + + /* Write the ELF object. */ + elf_update(elf, ELF_C_WRITE); + elf_end(elf); - if (mod && elf_update(elf, ELF_C_WRITE) == -1) - goto err; + return 0; - elf_end(elf); - close(fd); +fail: + if (usdt) { + if (elf) + elf_end(elf); - while ((pair = bufs) != NULL) { - bufs = pair->dlp_next; - dt_free(dtp, pair->dlp_str); - dt_free(dtp, pair->dlp_sym); - dt_free(dtp, pair); + dt_free(dtp, usdt); } - return 0; - -err: - return dt_link_error(dtp, elf, fd, bufs, - "an error was encountered while processing %s", obj); + return -1; } int @@ -1495,11 +414,10 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, const char *file, int objc, char *const objv[]) { char drti[PATH_MAX], symvers[PATH_MAX]; - dof_hdr_t *dof; - int fd, status, i, cur; + int fd, i, cur; char *cmd; size_t len; - int eprobes = 0, ret = 0; + int ret = 0, status = 0; /* * A NULL program indicates a special use in which we just link @@ -1522,17 +440,17 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, cur += snprintf(cmd + cur, len - cur, " %s", objv[i]); if ((status = system(cmd)) == -1) - return dt_link_error(dtp, NULL, -1, NULL, + return dt_link_error(dtp, NULL, -1, "failed to run %s: %s", dtp->dt_ld_path, strerror(errno)); if (WIFSIGNALED(status)) - return dt_link_error(dtp, NULL, -1, NULL, + return dt_link_error(dtp, NULL, -1, "failed to link %s: %s failed due to signal %d", file, dtp->dt_ld_path, WTERMSIG(status)); if (WEXITSTATUS(status) != 0) - return dt_link_error(dtp, NULL, -1, NULL, + return dt_link_error(dtp, NULL, -1, "failed to link %s: %s exited with status %d\n", file, dtp->dt_ld_path, WEXITSTATUS(status)); @@ -1543,40 +461,13 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, return 0; } - for (i = 0; i < objc; i++) { - if (process_obj(dtp, objv[i], &eprobes) != 0) - return -1; /* errno is set for us */ - - /* - * If there are is-enabled probes then we need to error out if - * DOF version 2 was used, preventing linkage of pre-existing - * objects that contain return-value-driven is-enabled probes - * with a DTrace that implements argument-driven is-enabled - * probes. (New objects will at this stage have DOF version 1.) - */ - if (eprobes && pgp->dp_dofversion == DOF_VERSION_2) - return dt_link_error(dtp, NULL, -1, NULL, - "DOF in %s is too old: regenerate with dtrace -G", - objv[i]); - } - - /* - * If there are is-enabled probes then we need to force use of DOF - * version 3. - */ - if (eprobes && pgp->dp_dofversion < DOF_VERSION_3) - pgp->dp_dofversion = DOF_VERSION_3; - - if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL) - return -1; /* errno is set for us */ - /* * Create a temporary file and then unlink it if we're going to * combine it with drti.o later. We can still refer to it in child * processes as /dev/fd/. */ if ((fd = open64(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) - return dt_link_error(dtp, NULL, -1, NULL, + return dt_link_error(dtp, NULL, -1, "failed to open %s: %s", file, strerror(errno)); /* @@ -1585,37 +476,26 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, */ switch (dtp->dt_linktype) { case DT_LTYP_DOF: - if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) - ret = errno; - - if (close(fd) != 0 && ret == 0) - ret = errno; - - if (ret != 0) - return dt_link_error(dtp, NULL, -1, NULL, - "failed to write %s: %s", file, strerror(ret)); - - return 0; + return dt_link_error(dtp, NULL, -1, + "link type %u (DOF) no longer supported\n", + dtp->dt_linktype); case DT_LTYP_ELF: break; /* fall through to the rest of dtrace_program_link() */ default: - return dt_link_error(dtp, NULL, -1, NULL, - "invalid link type %u\n", dtp->dt_linktype); + return dt_link_error(dtp, NULL, -1, "invalid link type %u\n", + dtp->dt_linktype); } if (!dtp->dt_lazyload) unlink(file); - if (dtp->dt_oflags & DTRACE_O_ILP32) - status = dump_elf32(dtp, dof, fd); - else - status = dump_elf64(dtp, dof, fd); + create_elf64(dtp, pgp, fd, dflags | dtp->dt_dflags); if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) - return dt_link_error(dtp, NULL, -1, NULL, + return dt_link_error(dtp, NULL, -1, "failed to write %s: %s", file, strerror(errno)); if (!dtp->dt_lazyload) { @@ -1650,7 +530,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, symvers, fd, drti); if ((status = system(cmd)) == -1) { - ret = dt_link_error(dtp, NULL, -1, NULL, + ret = dt_link_error(dtp, NULL, -1, "failed to run %s: %s", dtp->dt_ld_path, strerror(errno)); goto done; @@ -1659,14 +539,14 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, close(fd); if (WIFSIGNALED(status)) { - ret = dt_link_error(dtp, NULL, -1, NULL, + ret = dt_link_error(dtp, NULL, -1, "failed to link %s: %s failed due to signal %d", file, dtp->dt_ld_path, WTERMSIG(status)); goto done; } if (WEXITSTATUS(status) != 0) { - ret = dt_link_error(dtp, NULL, -1, NULL, + ret = dt_link_error(dtp, NULL, -1, "failed to link %s: %s exited with status %d\n", file, dtp->dt_ld_path, WEXITSTATUS(status)); goto done; @@ -1675,6 +555,5 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, close(fd); /* release temporary file */ done: - dtrace_dof_destroy(dtp, dof); return ret; } diff --git a/libdtrace/dt_program.c b/libdtrace/dt_program.c index d1c5272b..a2d1918a 100644 --- a/libdtrace/dt_program.c +++ b/libdtrace/dt_program.c @@ -356,7 +356,9 @@ dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data) dtrace_hdl_t *dtp = infop->dthi_dtp; dt_probe_t *prp = idp->di_data; dt_node_t *dnp; +#if 0 char buf[DT_TYPE_NAMELEN]; +#endif char *fname; const char *p; int i; @@ -368,15 +370,28 @@ dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data) fname = alloca(strlen(prp->pr_name) + 1 + i); dt_header_fmt_func(fname, prp->pr_name); - if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(", + if (fprintf(infop->dthi_out, "extern void __usdt1_%s___%s(", infop->dthi_pfname, fname) < 0) return dt_set_errno(dtp, errno); + /* + * Generate a function prototype with void * as type for each probe + * argument. This is used as a "trick" to ensure that probe invocation + * using the DTRACE_PROBE() macro pass the correct number of arguments. + * (That macro defines the same function prototype, with the number of + * arguments passed, so the compiler will complain if they do not + * match.) + */ for (dnp = prp->nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) { +#if 0 if (fprintf(infop->dthi_out, "%s", ctf_type_name(dnp->dn_ctfp, dnp->dn_type, buf, sizeof(buf))) < 0) return dt_set_errno(dtp, errno); +#else + if (fprintf(infop->dthi_out, "unsigned long") < 0) + return dt_set_errno(dtp, errno); +#endif if (i + 1 < prp->nargc && fprintf(infop->dthi_out, ", ") < 0) @@ -389,10 +404,17 @@ dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data) if (fprintf(infop->dthi_out, ");\n") < 0) return dt_set_errno(dtp, errno); +#if 0 if (fprintf(infop->dthi_out, - "extern void __dtraceenabled_%s___%s(uint32_t *flag);\n", + "extern void __usdt2_%s___%s(uint32_t *flag);\n", infop->dthi_pfname, fname) < 0) return dt_set_errno(dtp, errno); +#else + if (fprintf(infop->dthi_out, + "extern void __usdt2_%s___%s(unsigned long);\n", + infop->dthi_pfname, fname) < 0) + return dt_set_errno(dtp, errno); +#endif return 0; } @@ -435,16 +457,18 @@ dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) if (fprintf(infop->dthi_out, ") \\\n\t") < 0) return dt_set_errno(dtp, errno); +#if 0 if (fprintf(infop->dthi_out, "__dtrace_%s___%s(", infop->dthi_pfname, fname) < 0) return dt_set_errno(dtp, errno); +#else + if (fprintf(infop->dthi_out, "_USDT_PROBE(%s, %s", + infop->dthi_pfname, fname) < 0) + return dt_set_errno(dtp, errno); +#endif for (i = 0; i < prp->nargc; i++) { - if (fprintf(infop->dthi_out, "arg%d", i) < 0) - return dt_set_errno(dtp, errno); - - if (i + 1 != prp->nargc && - fprintf(infop->dthi_out, ", ") < 0) + if (fprintf(infop->dthi_out, ", arg%d", i) < 0) return dt_set_errno(dtp, errno); } } @@ -457,11 +481,10 @@ dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data) "#ifdef __GNUC__\n" "#define\t%s_%s_ENABLED() \\\n" "\t({ uint32_t enabled = 0; \\\n" - "\t__dtraceenabled_%s___%s(&enabled); \\\n" + "\t _USDT_PROBE_ENABLED(%s, %s, &enabled); \\\n" "\t enabled; })\n" "#else\n" - "#define\t%s_%s_ENABLED() (1)\\n" - "#endif\n" + "#define\t%s_%s_ENABLED() (1)\n" "#endif\n", infop->dthi_pmname, mname, infop->dthi_pfname, fname, @@ -486,6 +509,8 @@ dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out) if (pvp->pv_flags & DT_PROVIDER_IMPL) return 0; + if (!dt_idhash_size(pvp->pv_probes)) + return 0; /* * Count the instances of the '-' character since we'll need to double @@ -548,7 +573,8 @@ dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname) } if (fprintf(out, "#include \n" - "#include \n\n") < 0) + "#include \n" + "#include \n\n") < 0) return -1; if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0) diff --git a/test/triggers/Build b/test/triggers/Build index 3b5df3ec..d49b996a 100644 --- a/test/triggers/Build +++ b/test/triggers/Build @@ -1,5 +1,5 @@ # Oracle Linux DTrace. -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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. @@ -13,7 +13,9 @@ EXTERNAL_64BIT_TRIGGERS = testprobe readwholedir mmap bogus-ioctl open delaydie ustack-tst-spin ustack-tst-mtspin \ visible-constructor visible-constructor-static visible-constructor-static-unstripped -EXTERNAL_64BIT_SDT_TRIGGERS = usdt-tst-argmap usdt-tst-args usdt-tst-forker usdt-tst-defer \ +EXTERNAL_64BIT_SDT_TRIGGERS = usdt-tst-argmap usdt-tst-args \ + usdt-tst-arg-const usdt-tst-arg-reg \ + usdt-tst-deref-decode usdt-tst-forker usdt-tst-defer \ usdt-tst-multiprovider usdt-tst-multiprov-dupprobe usdt-tst-special EXTERNAL_64BIT_TRIGGERS += $(EXTERNAL_64BIT_SDT_TRIGGERS) @@ -197,10 +199,23 @@ profile-tst-ufuncsort_CFLAGS := -O0 usdt-tst-argmap_CFLAGS := -Iuts/common usdt-tst-argmap_PROV := usdt-tst-argmap-prov.d +# usdt-tst-deref-decode calls USDT probes using sys/sdt.h +usdt-tst-deref-decode_CFLAGS := -Iuts/common -O3 +usdt-tst-deref-decode_SOURCES := usdt-tst-deref-decode.${ARCH}.c +usdt-tst-deref-decode_PROV := usdt-tst-deref-decode-prov.d + # usdt-tst-args calls USDT probes using sys/sdt.h usdt-tst-args_CFLAGS := -Iuts/common usdt-tst-args_PROV := usdt-tst-args-prov.d +# usdt-tst-args-const calls USDT probes based on dtrace -h +usdt-tst-arg-const_CFLAGS := -Iuts/common +usdt-tst-arg-const_PROV := usdt-tst-arg-const-prov.d + +# usdt-tst-args-reg calls USDT probes based on dtrace -h +usdt-tst-arg-reg_CFLAGS := -Iuts/common -O0 +usdt-tst-arg-reg_PROV := usdt-tst-arg-reg-prov.d + # usdt-tst-forker calls USDT probes based on dtrace -h usdt-tst-forker_PROV := usdt-tst-forker-prov.d diff --git a/test/triggers/usdt-tst-arg-const-prov.d b/test/triggers/usdt-tst-arg-const-prov.d new file mode 100644 index 00000000..915a61da --- /dev/null +++ b/test/triggers/usdt-tst-arg-const-prov.d @@ -0,0 +1,19 @@ +/* + * 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. + */ + +/* @@skip: provider declaration - not a test */ + +provider test_prov { + probe uval1(uint8_t a); + probe sval1(int8_t a); + probe uval2(uint16_t a); + probe sval2(int16_t a); + probe uval4(uint32_t a); + probe sval4(int32_t a); + probe uval8(uint64_t a); + probe sval8(int64_t a); +}; diff --git a/test/triggers/usdt-tst-arg-const.c b/test/triggers/usdt-tst-arg-const.c new file mode 100644 index 00000000..e0cbfa1e --- /dev/null +++ b/test/triggers/usdt-tst-arg-const.c @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#include "usdt-tst-arg-const-prov.h" + +int +main(int argc, char **argv) +{ + for (;;) { + TEST_PROV_UVAL1(0x12); + TEST_PROV_SVAL1(-0x12); + TEST_PROV_UVAL2(0x1234); + TEST_PROV_SVAL2(-0x1234); + TEST_PROV_UVAL4(0x12345678); + TEST_PROV_SVAL4(-0x12345678); + TEST_PROV_UVAL8(0x1234567890abcdefULL); + TEST_PROV_SVAL8(-0x1234567890abcdefLL); + } + + return 0; +} diff --git a/test/triggers/usdt-tst-arg-reg-prov.d b/test/triggers/usdt-tst-arg-reg-prov.d new file mode 100644 index 00000000..915a61da --- /dev/null +++ b/test/triggers/usdt-tst-arg-reg-prov.d @@ -0,0 +1,19 @@ +/* + * 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. + */ + +/* @@skip: provider declaration - not a test */ + +provider test_prov { + probe uval1(uint8_t a); + probe sval1(int8_t a); + probe uval2(uint16_t a); + probe sval2(int16_t a); + probe uval4(uint32_t a); + probe sval4(int32_t a); + probe uval8(uint64_t a); + probe sval8(int64_t a); +}; diff --git a/test/triggers/usdt-tst-arg-reg.c b/test/triggers/usdt-tst-arg-reg.c new file mode 100644 index 00000000..ed8e097c --- /dev/null +++ b/test/triggers/usdt-tst-arg-reg.c @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#define _DT_ARG_CONSTRAINT r +#include "usdt-tst-arg-reg-prov.h" + +int +main(int argc, char **argv) +{ + uint8_t a = 0x12; + int8_t b = -0x12; + uint16_t c = 0x1234; + int16_t d = -0x1234; + uint32_t e = 0x12345678; + int32_t f = -0x12345678; + uint64_t g = 0x1234567890abcdefULL; + int64_t h = -0x1234567890abcdefLL; + + for (;;) { + TEST_PROV_UVAL1(a); + TEST_PROV_SVAL1(b); + TEST_PROV_UVAL2(c); + TEST_PROV_SVAL2(d); + TEST_PROV_UVAL4(e); + TEST_PROV_SVAL4(f); + TEST_PROV_UVAL8(g); + TEST_PROV_SVAL8(h); + } + + return 0; +} diff --git a/test/triggers/usdt-tst-deref-decode-prov.d b/test/triggers/usdt-tst-deref-decode-prov.d new file mode 100644 index 00000000..1456e274 --- /dev/null +++ b/test/triggers/usdt-tst-deref-decode-prov.d @@ -0,0 +1,11 @@ +/* + * 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. + */ + +provider test_prov { + probe deref(int64_t a, int64_t b, int64_t c, int64_t d, int64_t e, + int64_t f, int64_t g, int64_t h, int64_t i, int64_t j); +}; diff --git a/test/triggers/usdt-tst-deref-decode.aarch64.c b/test/triggers/usdt-tst-deref-decode.aarch64.c new file mode 100644 index 00000000..70343e0b --- /dev/null +++ b/test/triggers/usdt-tst-deref-decode.aarch64.c @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#include +#include + +int +main(int argc, char **argv) +{ + int *stp = calloc(100, sizeof(int)); + long i = 0; + + for (i = 0; i < 100; i++) + stp[i] = (i % 2 == 0) ? i : -i; + + i = 0; + for (;;) { + /* + * Using pre-generated macro expansions because we need to force specific + * expresisons for the probe argument to exercise the decoder. + */ + do { + /* extern void __usdt1_test_prov___deref(unsigned long); */ + __asm__ __volatile__ ( + ".altmacro" "\n" + ".macro _SST x y z" "\n" + ".iflt \\x" "\n" + ".ascii \"-\"" "\n" + ".endif" "\n" + ".ascii \"\\y\"" "\n" + ".ifc 8,\\z" "\n" + ".ascii \"f\"" "\n" + ".endif" "\n" + ".ascii \"@\"" "\n" + ".endm" "\n" + ".macro SST x" "\n" + "_SST \\x, %%(-(\\x*((\\x>0)-(\\x<0)))>>8), %%((\\x))&(0xff)" "\n" + ".endm" "\n" + "mov x8, %[i]" "\n" + "mov x9, %[stp]" "\n" + "lsl x7, x8, #2" "\n" + "0: nop" "\n" + ".pushsection .note.usdt,\"?\", at note" "\n" + ".balign 4" "\n" + ".4byte 2f-1f" "\n" + ".4byte 4f-3f" "\n" + ".4byte 1" "\n" + "1: .asciz \"usdt\"" "\n" + "2: .balign 4" "\n" + "3: .8byte 0b" "\n" + ".8byte %[fn]" "\n" + ".asciz \"test_prov\"" "\n" + ".asciz \"deref\"" "\n" + ".byte 10" "\n" + ".ascii \"-4@[x9,x7,4] \"" "\n" + ".ascii \"-4@[x9,x8,4] \"" "\n" + ".ascii \"-4 at 52 \"" "\n" + ".ascii \"-4@[x9,4] \"" "\n" + ".ascii \"-4@[x9,x7] \"" "\n" + ".ascii \"-4@[x9,x8] \"" "\n" + ".ascii \"-8 at x7 \"" "\n" + ".ascii \"-4@[x9] \"" "\n" + ".ascii \"-8 at x9 \"" "\n" + ".ascii \"-8 at x8\"" "\n" + ".byte 0" "\n" + "4: .balign 4" "\n" + ".popsection" "\n" + ".purgem SST" "\n" + ".purgem _SST" "\n" + :: [i] "r" (i), + [stp] "r" (stp), + [fn] "s" (__func__) + : "x7", "x8", "x9" ); + } while (0); + + if (++i >= 25) + i = 0; + } + return 0; +} diff --git a/test/triggers/usdt-tst-deref-decode.x86_64.c b/test/triggers/usdt-tst-deref-decode.x86_64.c new file mode 100644 index 00000000..66a76789 --- /dev/null +++ b/test/triggers/usdt-tst-deref-decode.x86_64.c @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#include +#include + +int +main(int argc, char **argv) +{ + int *stp = calloc(100, sizeof(int)); + long i = 0; + + for (i = 0; i < 100; i++) + stp[i] = (i % 2 == 0) ? i : -i; + + for (;;) { + /* + * Using pre-generated macro expansions because we need to force specific + * expresisons for the probe argument to exercise the decoder. + */ + do { + /* extern void __usdt1_test_prov___deref(unsigned long); */ + __asm__ __volatile__ ( + ".altmacro" "\n" + ".macro _SST x y z" "\n" + ".iflt \\x" "\n" + ".ascii \"-\"" "\n" + ".endif" "\n" + ".ascii \"\\y\"" "\n" + ".ifc 8,\\z" "\n" + ".ascii \"f\"" "\n" + ".endif" "\n" + ".ascii \"@\"" "\n" + ".endm" "\n" + ".macro SST x" "\n" + "_SST \\x, %%(-(\\x*((\\x>0)-(\\x<0)))>>8), %%((\\x))&(0xff)" "\n" + ".endm" "\n" + "0: nop" "\n" + ".pushsection .note.usdt,\"?\", at note" "\n" + ".balign 4" "\n" + ".4byte 2f-1f" "\n" + ".4byte 4f-3f" "\n" + ".4byte 1" "\n" + "1: .asciz \"usdt\"" "\n" + "2: .balign 4" "\n" + "3: .8byte 0b" "\n" + ".8byte %p[fn]" "\n" + ".asciz \"test_prov\"" "\n" + ".asciz \"deref\"" "\n" + ".byte 10" "\n" + ".ascii \"-4 at 4(%%rcx,%%rdx,4) \"" "\n" + ".ascii \"-4 at 4(%%rcx,%%rdx) \"" "\n" + ".ascii \"-8 at 4(,%%rdx,4) \"" "\n" + ".ascii \"-4 at 4(%%rcx) \"" "\n" + ".ascii \"-4@(%%rcx,%%rdx,4) \"" "\n" + ".ascii \"-4@(%%rcx,%%rdx) \"" "\n" + ".ascii \"-8@(,%%rdx,4) \"" "\n" + ".ascii \"-4@(%%rcx) \"" "\n" + ".ascii \"-8@%%rcx \"" "\n" + ".ascii \"-8@%%rdx\"" "\n" + ".byte 0" "\n" + "4: .balign 4" "\n" + ".popsection" "\n" + ".purgem SST" "\n" + ".purgem _SST" "\n" + :: [arr] "c" (stp), + [idx] "d" (i), + [fn] "s" (__func__) ); + } while (0); + + if (++i >= 25) + i = 0; + } + + return 0; +} diff --git a/test/unittest/options/tst.strip.sh b/test/unittest/options/tst.strip.sh index f7960d7a..d25f76af 100755 --- a/test/unittest/options/tst.strip.sh +++ b/test/unittest/options/tst.strip.sh @@ -45,20 +45,20 @@ if [ $? -ne 0 ]; then exit 1 fi -# link with and without -xstrip, dumping the DOF section +# link with and without -xstrip, dumping the USDT note -objdump="${OBJDUMP} --full-contents --section=.SUNW_dof prov.o" +objdump="${OBJDUMP} --full-contents --section=.note.usdt prov.o" $dtrace $dt_flags -G -xstrip -s prov.d test.o if [ $? -ne 0 ]; then - echo "failed to create DOF (stripped)" >& 2 + echo "failed to create USDT notes (stripped)" >& 2 exit 1 fi $objdump >& out.stripped.txt $dtrace $dt_flags -G -s prov.d test.o if [ $? -ne 0 ]; then - echo "failed to create DOF" >& 2 + echo "failed to create USDT notes" >& 2 exit 1 fi $objdump >& out.default.txt diff --git a/test/unittest/usdt/tst.guess32.sh b/test/unittest/usdt/err.wrong-probe-argc-cc.sh similarity index 57% rename from test/unittest/usdt/tst.guess32.sh rename to test/unittest/usdt/err.wrong-probe-argc-cc.sh index 21961236..73e11f9b 100755 --- a/test/unittest/usdt/tst.guess32.sh +++ b/test/unittest/usdt/err.wrong-probe-argc-cc.sh @@ -1,49 +1,45 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. +# 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. - +# if [ $# != 1 ]; then echo expected one argument: '<'dtrace-path'>' exit 2 fi dtrace=$1 +CC=/usr/bin/gcc CFLAGS="$test_cppflags" LDFLAGS="$test_ldflags" -DIRNAME="$tmpdir/usdt-guess32.$$.$RANDOM" +DIRNAME="$tmpdir/usdt-wrong-probe.$$.$RANDOM" mkdir -p $DIRNAME cd $DIRNAME cat > prov.d <& 2 - exit 1 -fi - cat > test.c < +#include #include "prov.h" int main(int argc, char **argv) { - if (TEST_PROV_GO_ENABLED()) { - TEST_PROV_GO(); - } + DTRACE_PROBE(test_prov, go, 1); + + return 0; } EOF -${CC} ${CFLAGS} -m32 -c test.c +$dtrace $dt_flags -h -s prov.d +${CC} ${CFLAGS} -c test.c if [ $? -ne 0 ]; then echo "failed to compile test.c" >& 2 exit 1 @@ -53,23 +49,13 @@ if [ $? -ne 0 ]; then echo "failed to create DOF" >& 2 exit 1 fi -${CC} ${LDFLAGS} -m32 -o test test.o prov.o +${CC} ${LDFLAGS} -o test test.o prov.o if [ $? -ne 0 ]; then echo "failed to link final executable" >& 2 exit 1 fi -script() -{ - $dtrace $dt_flags -c ./test -qs /dev/stdin <' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="$test_cppflags" +LDFLAGS="$test_ldflags" + +DIRNAME="$tmpdir/usdt-wrong-probe.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > prov.d < test.c < + +int +main(int argc, char **argv) +{ + DTRACE_PROBE(test_prov, go, 1); + + return 0; +} +EOF + +${CC} ${CFLAGS} -c test.c +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi +$dtrace $dt_flags -G -s prov.d test.o +if [ $? -ne 0 ]; then + echo "failed to create DOF" >& 2 + exit 1 +fi +${CC} ${LDFLAGS} -o test test.o prov.o +if [ $? -ne 0 ]; then + echo "failed to link final executable" >& 2 + exit 1 +fi + +$dtrace $dt_flags -c ./test -n 'test_prov$target:::go, tick-1s { exit(0); }' +rc=$? + +exit $rc diff --git a/test/unittest/usdt/err.wrong-probe.sh b/test/unittest/usdt/err.wrong-probe.sh new file mode 100755 index 00000000..c7ae74f2 --- /dev/null +++ b/test/unittest/usdt/err.wrong-probe.sh @@ -0,0 +1,59 @@ +#!/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. +# +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="$test_cppflags" +LDFLAGS="$test_ldflags" + +DIRNAME="$tmpdir/usdt-wrong-probe.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > prov.d < test.c < + +int +main(int argc, char **argv) +{ + DTRACE_PROBE(test_prov, bad); + + return 0; +} +EOF + +${CC} ${CFLAGS} -c test.c +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi +$dtrace $dt_flags -G -s prov.d test.o +if [ $? -ne 0 ]; then + echo "failed to create DOF" >& 2 + exit 1 +fi +${CC} ${LDFLAGS} -o test test.o prov.o +if [ $? -ne 0 ]; then + echo "failed to link final executable" >& 2 + exit 1 +fi + +$dtrace $dt_flags -c ./test -n 'test_prov$target:::, tick-1s { exit(0); }' +rc=$? + +exit $rc diff --git a/test/unittest/usdt/err.wrong-prov.sh b/test/unittest/usdt/err.wrong-prov.sh new file mode 100755 index 00000000..4562a3ae --- /dev/null +++ b/test/unittest/usdt/err.wrong-prov.sh @@ -0,0 +1,59 @@ +#!/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. +# +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 +CC=/usr/bin/gcc +CFLAGS="$test_cppflags" +LDFLAGS="$test_ldflags" + +DIRNAME="$tmpdir/usdt-wrong-prov.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +cat > prov.d < test.c < + +int +main(int argc, char **argv) +{ + DTRACE_PROBE(bad_prov, go); + + return 0; +} +EOF + +${CC} ${CFLAGS} -c test.c +if [ $? -ne 0 ]; then + echo "failed to compile test.c" >& 2 + exit 1 +fi +$dtrace $dt_flags -G -s prov.d test.o +if [ $? -ne 0 ]; then + echo "failed to create DOF" >& 2 + exit 1 +fi +${CC} ${LDFLAGS} -o test test.o prov.o +if [ $? -ne 0 ]; then + echo "failed to link final executable" >& 2 + exit 1 +fi + +$dtrace $dt_flags -c ./test -n '*_prov$target:::, tick-1s { exit(0); }' +rc=$? + +exit $rc diff --git a/test/unittest/usdt/tst.arg-reg.d b/test/unittest/usdt/tst.arg-reg.d new file mode 100644 index 00000000..123e7e21 --- /dev/null +++ b/test/unittest/usdt/tst.arg-reg.d @@ -0,0 +1,38 @@ +/* + * 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: usdt-tst-arg-reg */ +/* @@trigger-timing: before */ +/* @@runtest-opts: $_pid */ + +#pragma D option quiet + +BEGIN +{ + /* Timeout after 5 seconds */ + timeout = timestamp + 5000000000; +} + +test_prov$1:::sval*, +test_prov$1:::uval* +/firings[probename]++/ +{ + exit(0); +} + +test_prov$1:::sval*, +test_prov$1:::uval* +{ + printf("%s: arg is %d\n", probename, arg0); +} + +profile:::tick-1 +/timestamp > timeout/ +{ + trace("test timed out"); + exit(1); +} diff --git a/test/unittest/usdt/tst.arg-reg.r b/test/unittest/usdt/tst.arg-reg.r new file mode 100644 index 00000000..ce792166 --- /dev/null +++ b/test/unittest/usdt/tst.arg-reg.r @@ -0,0 +1,9 @@ +uval1: arg is 18 +sval1: arg is -18 +uval2: arg is 4660 +sval2: arg is -4660 +uval4: arg is 305419896 +sval4: arg is -305419896 +uval8: arg is 1311768467294899695 +sval8: arg is -1311768467294899695 + diff --git a/test/unittest/usdt/tst.badguess.sh b/test/unittest/usdt/tst.badguess.sh deleted file mode 100755 index 6cd959bb..00000000 --- a/test/unittest/usdt/tst.badguess.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash -# -# Oracle Linux DTrace. -# Copyright (c) 2006, 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. -# -if [ $# != 1 ]; then - echo expected one argument: '<'dtrace-path'>' - exit 2 -fi - -dtrace=$1 -CFLAGS="$test_cppflags" -LDFLAGS="$test_ldflags" - -DIRNAME="$tmpdir/usdt-badguess.$$.$RANDOM" -mkdir -p $DIRNAME -cd $DIRNAME - -cat > prov.d <& 2 - exit 1 -fi - -cat > test.c < -#include "prov.h" - -int -main(int argc, char **argv) -{ - if (TEST_PROV_GO_ENABLED()) { - TEST_PROV_GO(); - } -} -EOF - -$CC $CFLAGS -c -o test64.o test.c -if [ $? -ne 0 ]; then - echo "failed to compile test.c 64-bit" >& 2 - exit 1 -fi -$CC $LDFLAGS -m32 -c -o test32.o test.c -if [ $? -ne 0 ]; then - echo "failed to compile test.c 32-bit" >& 2 - exit 1 -fi - -$dtrace $dt_flags -G -s prov.d test32.o test64.o -if [ $? -eq 0 ]; then - echo "DOF generation failed to generate a warning" >& 2 - exit 1 -fi - -exit 0 diff --git a/test/unittest/usdt/tst.badguess.x b/test/unittest/usdt/tst.badguess.x deleted file mode 100755 index b4030d55..00000000 --- a/test/unittest/usdt/tst.badguess.x +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. -# -# If we can't compile a trivial 32-bit program, this test -# will fail. -echo 'int main (void) { }' | $CC -x c -c -o /dev/null -m32 - 2>/dev/null diff --git a/test/unittest/usdt/tst.const.d b/test/unittest/usdt/tst.const.d new file mode 100644 index 00000000..515de7f8 --- /dev/null +++ b/test/unittest/usdt/tst.const.d @@ -0,0 +1,38 @@ +/* + * 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: usdt-tst-arg-const */ +/* @@trigger-timing: before */ +/* @@runtest-opts: $_pid */ + +#pragma D option quiet + +BEGIN +{ + /* Timeout after 5 seconds */ + timeout = timestamp + 5000000000; +} + +test_prov$1:::sval*, +test_prov$1:::uval* +/firings[probename]++/ +{ + exit(0); +} + +test_prov$1:::sval*, +test_prov$1:::uval* +{ + printf("%s: arg is %d\n", probename, arg0); +} + +profile:::tick-1 +/timestamp > timeout/ +{ + trace("test timed out"); + exit(1); +} diff --git a/test/unittest/usdt/tst.const.r b/test/unittest/usdt/tst.const.r new file mode 100644 index 00000000..ce792166 --- /dev/null +++ b/test/unittest/usdt/tst.const.r @@ -0,0 +1,9 @@ +uval1: arg is 18 +sval1: arg is -18 +uval2: arg is 4660 +sval2: arg is -4660 +uval4: arg is 305419896 +sval4: arg is -305419896 +uval8: arg is 1311768467294899695 +sval8: arg is -1311768467294899695 + diff --git a/test/unittest/usdt/tst.deref-decode.d b/test/unittest/usdt/tst.deref-decode.d new file mode 100644 index 00000000..fc019eb5 --- /dev/null +++ b/test/unittest/usdt/tst.deref-decode.d @@ -0,0 +1,39 @@ +/* + * 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: usdt-tst-deref-decode */ +/* @@trigger-timing: before */ +/* @@runtest-opts: $_pid */ + +#pragma D option quiet + +BEGIN +{ + /* Timeout after 5 seconds */ + timeout = timestamp + 5000000000; +} + +test_prov$1:::deref +/arg9 == 12 && (arg0 != -13 || arg1 != 4 || arg2 != 52 || arg3 != -1 || + arg4 != 12 || arg5 != -3 || arg6 != 48 || arg7 != 0)/ +{ + printf("args are %d %d %d %d %d %d %d %d %d; should be -13 4 52 -1 12 -3 48 0 12", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg9); + exit(1); +} + +test_prov$1:::deref +/arg9 == 12/ +{ + exit(0); +} + +profile:::tick-1 +/timestamp > timeout/ +{ + trace("test timed out"); + exit(1); +} diff --git a/test/unittest/usdt/tst.guess32.x b/test/unittest/usdt/tst.guess32.x deleted file mode 100755 index a0b1b73e..00000000 --- a/test/unittest/usdt/tst.guess32.x +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -# Licensed under the Universal Permissive License v 1.0 as shown at -# http://oss.oracle.com/licenses/upl. -# -# The existence of this file is a reasonable proxy for -# being on a 32-bit-capable host. -[[ -e test/triggers/libproc-sleeper-32 ]] && exit 0 -exit 1 diff --git a/test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p b/test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p index ff7128a2..3018b827 100755 --- a/test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p +++ b/test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p @@ -1,5 +1,9 @@ #!/usr/bin/gawk -f +# Initialize tgt to a dummy value so output without a correct first line does +# not result in trying to replace every character in output with $target. +BEGIN { tgt = "DUMMY"; } + # first line: get the target pid /^target = [0-9]*$/ { tgt = $3; next } diff --git a/test/utils/Build b/test/utils/Build index 10f4e726..7976272f 100644 --- a/test/utils/Build +++ b/test/utils/Build @@ -1,5 +1,5 @@ # Oracle Linux DTrace. -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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. @@ -31,8 +31,8 @@ $(foreach util,$(TEST_UTILS),$(eval $(call test-util-template,$(util)))) # The showUSDT utility needs to be linked against libelf, and should not be # linked against libdtrace. -showUSDT_DEPS = -showUSDT_LIBS = -lelf +showUSDT_DEPS = libcommon.a +showUSDT_LIBS = -lelf -L$(objdir) -lcommon # The print-stack-layout utility needs dt_impl.h which needs dt_git_version.h. print-stack-layout_SRCDEPS := $(objdir)/dt_git_version.h diff --git a/test/utils/showUSDT.c b/test/utils/showUSDT.c index 3ab2632e..63abc602 100644 --- a/test/utils/showUSDT.c +++ b/test/utils/showUSDT.c @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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. */ @@ -15,12 +15,30 @@ #include #include +#include + +#include + #ifndef SHT_SUNW_dof # define SHT_SUNW_dof 0x6ffffff4 #endif +#define ALIGN(v, p2) (((v) + ((p2) - 1)) & ~((p2) - 1)) + static int arch; +void *dt_alloc(void *dmy, size_t size) { + return malloc(size); +} + +void *dt_calloc(void *dmy, size_t num, size_t size) { + return calloc(num, size); +} + +void dt_free(void *dmy, void *ptr) { + free(ptr); +} + static void printComments(dof_sec_t *sec, void *data) { printf(" Comment:\n" \ " %s\n", (char *)data + sec->dofs_offset); @@ -349,10 +367,273 @@ static int processDOF(dof_hdr_t *dof, size_t size) { return 0; } +typedef struct dt_probe dt_probe_t; +typedef struct dt_provider dt_provider_t; + +struct dt_probe { + dt_hentry_t he; + dt_provider_t *prov; + const char *prv; + const char *fun; + const char *prb; +}; + +struct dt_provider { + dt_hentry_t he; + const char *name; + uint32_t pattr; + uint32_t mattr; + uint32_t fattr; + uint32_t nattr; + uint32_t aattr; + uint32_t probec; + dt_htab_t *pmap; + dt_probe_t *probes; +}; + +dt_htab_t *prvmap; +dt_htab_t *prbmap; + +extern uint32_t str2hval(const char *, uint32_t); + +static uint32_t prv_hval(const dt_provider_t *pvp) { + return str2hval(pvp->name, 0); +} + +static int prv_cmp(const dt_provider_t *p, const dt_provider_t *q) { + return strcmp(p->name, q->name); +} + +DEFINE_HE_STD_LINK_FUNCS(prv, dt_provider_t, he) +DEFINE_HTAB_STD_OPS(prv) + +static uint32_t prb_hval(const dt_probe_t *prp) { + uint32_t hval; + + hval = str2hval(prp->prv, 0); + hval = str2hval(prp->fun, hval); + + return str2hval(prp->prb, hval); +} + +static int prb_cmp(const dt_probe_t *p, const dt_probe_t *q) { + int rc; + + if (p->fun != NULL) { + if (q->fun == NULL) + return 1; + else { + rc = strcmp(p->fun, q->fun); + if (rc != 0) + return rc; + } + } else if (q->fun == NULL) + return -1; + + return strcmp(p->prb, q->prb); +} + +DEFINE_HE_STD_LINK_FUNCS(prb, dt_probe_t, he) +DEFINE_HTAB_STD_OPS(prb) + +static int processNote(const char *name, int type, const char *data, int size, + Elf_Data *rodata) { + int i; + dt_probe_t prbt, *prp; + dt_provider_t prvt, *prov; + + printf(" Note %s, type %d:\n", name, type); + if (strcmp(name, "usdt") == 0) { + const char *p = data; + uint64_t off, fno; + const char *prv, *fun, *prb; + + off = *(uint64_t *)p; + p += 8; + fno = *(uint64_t *)p; + p += 8; + + if (fno < rodata->d_off) + return -1; + fno -= rodata->d_off; + if (fno >= rodata->d_size) + return -1; + + fun = &((char *)rodata->d_buf)[fno]; + + printf(" Offset %#lx\n", off); + printf(" Function Offset %#lx\n", fno); + prv = p; + p += strlen(p) + 1; + prb = p; + p += strlen(p) + 1; + printf(" Probe %s::%s:%s%s\n", prv, fun, prb, type == 2 ? " (is-enabled)" : ""); + printf(" "); + + prvt.name = prv; + prov = dt_htab_lookup(prvmap, &prvt); + if (prov == NULL) { + prov = malloc(sizeof(dt_provider_t)); + memset(prov, 0, sizeof(dt_provider_t)); + prov->name = prv; + dt_htab_insert(prvmap, prov); + prov->pmap = dt_htab_create(&prb_htab_ops); + } + + prbt.prv = prv; + prbt.fun = fun; + prbt.prb = prb; + + prp = dt_htab_lookup(prbmap, &prbt); + if (prp == NULL) { + prp = malloc(sizeof(dt_probe_t)); + memset(prp, 0, sizeof(dt_probe_t)); + prp->prv = prov->name; + prp->fun = fun; + prp->prb = prb; + dt_htab_insert(prbmap, prp); + } + + for (i = p - data; i < size; i++) + printf("%c", isprint(data[i]) ? data[i] : '.'); + printf("\n"); + } else if (strcmp(name, "prov") == 0) { + const char *p = data; + const uint32_t *attr; + dt_provider_t *prov; + + prvt.name = p; + prov = dt_htab_lookup(prvmap, &prvt); + if (prov == NULL) { + prov = malloc(sizeof(dt_provider_t)); + memset(prov, 0, sizeof(dt_provider_t)); + prov->name = p; + dt_htab_insert(prvmap, prov); + prov->pmap = dt_htab_create(&prb_htab_ops); + } + + p += ALIGN(strlen(p) + 1, 4); + attr = (uint32_t *)ALIGN((uintptr_t)p, 4); + prov->pattr = *attr++; + prov->mattr = *attr++; + prov->fattr = *attr++; + prov->nattr = *attr++; + prov->aattr = *attr++; + prov->probec = *attr++; + printf(" Provider '%s' with %d probe%s:\n", + prov->name, prov->probec, prov->probec == 1 ? "" : "s"); + + p = (char *)attr; + for (i = 0; i < prov->probec; i++) { + int j, argc; + + p = (const char *)ALIGN((uintptr_t)p, 4); + prbt.prv = prov->name; + prbt.fun = NULL; + prbt.prb = p; + + prp = dt_htab_lookup(prov->pmap, &prbt); + if (prp == NULL) { + prp = malloc(sizeof(dt_probe_t)); + memset(prp, 0, sizeof(dt_probe_t)); + prp->prv = prov->name; + prp->fun = NULL; + prp->prb = p; + dt_htab_insert(prov->pmap, prp); + } + + printf(" Probe %d: %s:::%s\n", i, prp->prv, prp->prb); + + p += strlen(p) + 1; + argc = *(uint8_t *)p++; + + for (j = 0; j < argc; j++) { + printf(" (native) argv[%d]: %s\n", j, p); + p += strlen(p) + 1; + } + + argc = *(uint8_t *)p++; + + for (j = 0; j < argc; j++) { + const char *arg; + uint8_t m; + + arg = p; + p += strlen(arg) + 1; + m = *p++; + printf(" (translated) argv[%d] (from native argv[%hhd]): %s\n", + j, m, arg); + } + } + } else if (strcmp(name, "dver") == 0) { + const char *p = data; + + printf(" %s:\n", p); + } else if (strcmp(name, "utsn") == 0) { + struct utsname *uts = (struct utsname *)(char *)data; + + printf(" UTS Name:\n" \ + " sysname = %s\n" \ + " nodename = %s\n" \ + " release = %s\n" \ + " version = %s\n" \ + " machine = %s\n", + uts->sysname, uts->nodename, uts->release, uts->version, + uts->machine); + } + + return 0; +} + +static int processNotes(char *data, size_t size, Elf_Data *rodata) { + size_t idx = 0; + int ret = 0; + dt_htab_next_t *hit; + dt_provider_t *pvp; + dt_probe_t *prp; + + prvmap = dt_htab_create(&prv_htab_ops); + prbmap = dt_htab_create(&prb_htab_ops); + + for (idx = 0; idx < size; ) { + int nsz, dsz, type; + + nsz = *((int *)&data[idx]); + dsz = *((int *)&data[idx + 4]); + type = *((int *)&data[idx + 8]); + + ret = processNote(&data[idx + 12], type, + &data[idx + 12 + ALIGN(nsz, 4)], dsz, rodata); + if (ret != 0) + break; + + idx += 12 + ALIGN(nsz, 4) + ALIGN(dsz, 4); + } + + printf("----------\n"); + /* List all providers. */ + hit = NULL; + while ((pvp = dt_htab_next(prvmap, &hit)) != NULL) { + printf(" Provider '%s' with %d probe%s:\n", + pvp->name, pvp->probec, pvp->probec == 1 ? "" : "s"); + } + + /* List all probes (to be added/validated) to providers. */ + hit = NULL; + while ((prp = dt_htab_next(prbmap, &hit)) != NULL) { + printf(" Probe %s::%s:%s\n", prp->prv, prp->fun, prp->prb); + } + + return ret; +} + static int readObj(const char *fn) { - int fd; + int fd, i; int ret = 1; Elf *elf = NULL; + Elf_Data *strtab = NULL; + Elf_Data *rodata = NULL; + char *sname; Elf_Data *data; Elf_Scn *scn; GElf_Ehdr ehdr; @@ -381,10 +662,7 @@ static int readObj(const char *fn) { goto out; } switch (ehdr.e_machine) { - case EM_386: case EM_X86_64: - case EM_SPARC: - case EM_SPARCV9: case EM_AARCH64: arch = ehdr.e_machine; break; @@ -396,28 +674,94 @@ static int readObj(const char *fn) { printf("Processing %s:\n", fn); + /* Get the .shstrtab data. */ + for (i = 1, scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; i++) { + if (i == ehdr.e_shstrndx) + break; + } + if (scn == NULL || + gelf_getshdr(scn, &shdr) == NULL || + shdr.sh_type != SHT_STRTAB) { + printf(" Section .shstrtab not found!\n"); + goto out; + } + if ((strtab = elf_getdata(scn, NULL)) == NULL) { + printf(" Failed to read data for .shstrtab section!\n"); + goto out; + } + + /* Get the .rodata data. */ scn = NULL; while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) == NULL) goto err; - - if (shdr.sh_type == SHT_SUNW_dof) + if (shdr.sh_type != SHT_PROGBITS) + continue; + if (shdr.sh_name >= strtab->d_size) { + printf(" Invalid section name!\n"); + goto out; + } + sname = &((char *)strtab->d_buf)[shdr.sh_name]; + if (strcmp(sname, ".rodata") == 0) break; } - if (shdr.sh_type != SHT_SUNW_dof) { - printf(" No DOF section found!\n"); + if (scn == NULL) { + printf(" No .rodata section found!\n"); goto out; } - if ((data = elf_getdata(scn, NULL)) == NULL) { - printf(" Failed to read data for SUNW_dof section!\n"); + if ((rodata = elf_getdata(scn, NULL)) == NULL) { + printf(" Failed to read data for .rodata section!\n"); goto out; } - processDOF(data->d_buf, data->d_size); + /* (Ab)use the offset to store the load base for the data. */ + rodata->d_off = shdr.sh_addr; + + /* Process note sections. */ + scn = NULL; + while ((scn = elf_nextscn(elf, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) == NULL) + goto err; + + switch (shdr.sh_type) { + case SHT_NOTE: + if (shdr.sh_name >= strtab->d_size) { + printf(" Invalid section name!\n"); + goto out; + } + + sname = &((char *)strtab->d_buf)[shdr.sh_name]; + if (strcmp(sname, ".note.usdt") != 0) + continue; + + if ((data = elf_getdata(scn, NULL)) == NULL) { + printf(" Failed to read data for .note.usdt section!\n"); + goto out; + } + + ret = processNotes(data->d_buf, data->d_size, rodata); + if (ret != 0) + goto out; + + break; + case SHT_SUNW_dof: + if ((data = elf_getdata(scn, NULL)) == NULL) { + printf(" Failed to read data for .note.usdt section!\n"); + goto out; + } + + ret = processDOF(data->d_buf, data->d_size); + if (ret != 0) + goto out; + + break; + default: + continue; + } + } - ret = 0; goto out; err: printf(" An error was encountered while processing %s\n", fn); diff --git a/uts/common/sys/sdt.h b/uts/common/sys/sdt.h index ea46e56d..58f4b709 100644 --- a/uts/common/sys/sdt.h +++ b/uts/common/sys/sdt.h @@ -1,170 +1,15 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 exists for backwards compatibility only. */ + #ifndef _SYS_SDT_H_ #define _SYS_SDT_H_ -#ifdef __cplusplus -extern "C" { -#endif - -#if (__STDC_VERSION__ >= 199901L && __GNUC__ && !__STRICT_ANSI__) || defined(__cplusplus) - -#define __stringify_1(...) # __VA_ARGS__ -#define __stringify(...) __stringify_1(__VA_ARGS__) -#include - -#define __DTRACE_TYPE_UNSIGNED_LONG_EACH(x) unsigned long -#define __DTRACE_ULONG_CAST_EACH(x) (unsigned long)x - -#define DTRACE_PROBE(provider, name, ...) { \ - extern void __dtrace_##provider##___##name(__DTRACE_APPLY_DEFAULT(__DTRACE_TYPE_UNSIGNED_LONG_EACH, void, ## __VA_ARGS__)); \ - __dtrace_##provider##___##name(__DTRACE_APPLY(__DTRACE_ULONG_CAST_EACH, ## __VA_ARGS__)); \ -} - -#else - -#define DTRACE_PROBE(provider, name) { \ - extern void __dtrace_##provider##___##name(void); \ - __dtrace_##provider##___##name(); \ -} - -#endif - -/* - * For backward compatibility and pre-C99 compilers. - */ - -#define DTRACE_PROBE1(provider, name, arg1) { \ - extern void __dtrace_##provider##___##name(unsigned long); \ - __dtrace_##provider##___##name((unsigned long)arg1); \ -} - -#define DTRACE_PROBE2(provider, name, arg1, arg2) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long); \ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2); \ -} - -#define DTRACE_PROBE3(provider, name, arg1, arg2, arg3) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long, unsigned long); \ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2, (unsigned long)arg3); \ -} - -#define DTRACE_PROBE4(provider, name, arg1, arg2, arg3, arg4) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long, unsigned long, unsigned long); \ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2, (unsigned long)arg3, \ - (unsigned long)arg4); \ -} - -#define DTRACE_PROBE5(provider, name, arg1, arg2, arg3, arg4, arg5) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long);\ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2, (unsigned long)arg3, \ - (unsigned long)arg4, (unsigned long)arg5); \ -} - -#define DTRACE_PROBE6(provider, name, arg1, arg2, arg3, arg4, arg5, \ - arg6) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long, \ - unsigned long); \ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2, (unsigned long)arg3, \ - (unsigned long)arg4, (unsigned long)arg5, \ - (unsigned long)arg6); \ -} - -#define DTRACE_PROBE7(provider, name, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long, \ - unsigned long, unsigned long); \ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2, (unsigned long)arg3, \ - (unsigned long)arg4, (unsigned long)arg5, \ - (unsigned long)arg6, (unsigned long)arg7); \ -} - -#define DTRACE_PROBE8(provider, name, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7, arg8) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long, \ - unsigned long, unsigned long, unsigned long); \ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2, (unsigned long)arg3, \ - (unsigned long)arg4, (unsigned long)arg5, \ - (unsigned long)arg6, (unsigned long)arg7, \ - (unsigned long)arg8); \ -} - -#define DTRACE_PROBE9(provider, name, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7, arg8, arg9) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long);\ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2, (unsigned long)arg3, \ - (unsigned long)arg4, (unsigned long)arg5, \ - (unsigned long)arg6, (unsigned long)arg7, \ - (unsigned long)arg8, (unsigned long)arg9); \ -} - -#define DTRACE_PROBE10(provider, name, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7, arg8, arg9, arg10) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long, \ - unsigned long); \ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2, (unsigned long)arg3, \ - (unsigned long)arg4, (unsigned long)arg5, \ - (unsigned long)arg6, (unsigned long)arg7, \ - (unsigned long)arg8, (unsigned long)arg9, \ - (unsigned long)arg10); \ -} - -#define DTRACE_PROBE11(provider, name, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7, arg8, arg9, arg10, arg11) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long, \ - unsigned long, unsigned long); \ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2, (unsigned long)arg3, \ - (unsigned long)arg4, (unsigned long)arg5, \ - (unsigned long)arg6, (unsigned long)arg7, \ - (unsigned long)arg8, (unsigned long)arg9, \ - (unsigned long)arg10, (unsigned long)arg11); \ -} - -#define DTRACE_PROBE12(provider, name, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7, arg8, arg9, arg10, arg11, arg12) { \ - extern void __dtrace_##provider##___##name(unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long, \ - unsigned long, unsigned long, unsigned long, unsigned long, \ - unsigned long, unsigned long, unsigned long); \ - __dtrace_##provider##___##name((unsigned long)arg1, \ - (unsigned long)arg2, (unsigned long)arg3, \ - (unsigned long)arg4, (unsigned long)arg5, \ - (unsigned long)arg6, (unsigned long)arg7, \ - (unsigned long)arg8, (unsigned long)arg9, \ - (unsigned long)arg10, (unsigned long)arg11, \ - (unsigned long)arg12); \ -} - -#ifdef __cplusplus -} -#endif +#include #endif /* _SYS_SDT_H_ */ diff --git a/uts/common/sys/usdt.h b/uts/common/sys/usdt.h new file mode 100644 index 00000000..7913559c --- /dev/null +++ b/uts/common/sys/usdt.h @@ -0,0 +1,83 @@ +/* + * Oracle Linux DTrace. + * Copyright (c) 2011, 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. + */ + +#ifndef _SYS_USDT_H_ +#define _SYS_USDT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define __stringify_1(...) # __VA_ARGS__ +#define __stringify(...) __stringify_1(__VA_ARGS__) + +#include "usdt_gennote.h" + +#define __DT_TYPE_UNSIGNED_LONG_EACH(n, x) unsigned long +#define __DT_ULONG_CAST_EACH(n, x) (unsigned long)x + +#define DTRACE_PROBE(provider, name, ...) \ + _USDT_PROBE(provider, name, ## __VA_ARGS__) + +/* For backward compatibility and pre-C99 compilers. */ + +#define DTRACE_PROBE1(provider, name, arg1) \ + DTRACE_PROBE(provider, name, arg1) + +#define DTRACE_PROBE2(provider, name, arg1, arg2) \ + DTRACE_PROBE(provider, name, arg1, arg2) + +#define DTRACE_PROBE3(provider, name, arg1, arg2, arg3) \ + DTRACE_PROBE(provider, name, arg1, arg2, arg3) + +#define DTRACE_PROBE4(provider, name, arg1, arg2, arg3, arg4) \ + DTRACE_PROBE(provider, name, arg1, arg2, arg3, arg4) + +#define DTRACE_PROBE5(provider, name, arg1, arg2, arg3, arg4, arg5) \ + DTRACE_PROBE(provider, name, arg1, arg2, arg3, arg4, arg5) + +#define DTRACE_PROBE6(provider, name, arg1, arg2, arg3, arg4, arg5, \ + arg6) \ + DTRACE_PROBE(provider, name, arg1, arg2, arg3, arg4, \ + arg5, arg6) + +#define DTRACE_PROBE7(provider, name, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7) \ + DTRACE_PROBE(provider, name, arg1, arg2, arg3, arg4, \ + arg5, arg6, arg7) + +#define DTRACE_PROBE8(provider, name, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7, arg8) \ + DTRACE_PROBE(provider, name, arg1, arg2, arg3, arg4, \ + arg5, arg6, arg7, arg8) + +#define DTRACE_PROBE9(provider, name, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7, arg8, arg9) \ + DTRACE_PROBE(provider, name, arg1, arg2, arg3, arg4, \ + arg5, arg6, arg7, arg8, arg9) + +#define DTRACE_PROBE10(provider, name, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7, arg8, arg9, arg10) \ + DTRACE_PROBE(provider, name, arg1, arg2, arg3, arg4, \ + arg5, arg6, arg7, arg8, arg9, arg10) + +#define DTRACE_PROBE11(provider, name, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7, arg8, arg9, arg10, arg11) \ + DTRACE_PROBE(provider, name, arg1, arg2, arg3, arg4, \ + arg5, arg6, arg7, arg8, arg9, arg10, arg11) + +#define DTRACE_PROBE12(provider, name, arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7, arg8, arg9, arg10, arg11, arg12) \ + DTRACE_PROBE(provider, name, arg1, arg2, arg3, arg4, \ + arg5, arg6, arg7, arg8, arg9, arg10, \ + arg11, arg12) + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_USDT_H_ */ diff --git a/uts/common/sys/usdt_gennote.h b/uts/common/sys/usdt_gennote.h new file mode 100644 index 00000000..f063bc9d --- /dev/null +++ b/uts/common/sys/usdt_gennote.h @@ -0,0 +1,139 @@ +/* + * 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. + */ + +#ifndef _SYS_USDT_GENNOTE_H_ +#define _SYS_USDT_GENNOTE_H_ + +#include "usdt_internal.h" +#include "usdt_note_defs.h" + +#ifdef __aarch64__ +# define _DT_FN_MOD +# define _DT_FN_CONSTRAINT S +#else +# define _DT_FN_MOD p +# define _DT_FN_CONSTRAINT s +#endif + +#ifndef _DT_ARG_CONSTRAINT +# define _DT_ARG_CONSTRAINT nor +#endif + +#define __dt_s(...) # __VA_ARGS__ +#define _dt_s(...) __dt_s(__VA_ARGS__) + +#define _DT_ASM(...) __dt_s(__VA_ARGS__) "\n" + +/* XXX */ +#define _DT_INTTYPE(expr) \ + __typeof( \ + __builtin_choose_expr( \ + ((__builtin_classify_type(expr) + 3) & -4) == 4, (expr), 0UL \ + ) \ + ) +#define _DT_SIGNED(expr) \ + ((_DT_INTTYPE(expr))-1 < (_DT_INTTYPE(expr))0) +#define _DT_ARRAY(expr) \ + (__builtin_classify_type(expr) == 5 || __builtin_classify_type(expr) == 14) +#define _DT_SIZEOF(expr) \ + (_DT_ARRAY(expr) ? sizeof(void *) : sizeof(expr)) +#define _DT_TCLASS(expr) \ + (__builtin_classify_type(expr) & 0x7f) + +#define _DT_ARGSST(arg) \ + ( \ + (_DT_SIGNED(arg) ? -1 : 1) * \ + (((int)(_DT_SIZEOF(arg) << 8)) + ((int)_DT_TCLASS(arg))) \ + ) + +/* + * Assembler macros to construct the sign/size/type prefix for arguments: + * - '-' if the argument is signed (omitted for unsigned) + * - Then the size follows (in bytes) + * - Then 'f' if the argument is floating point (omitted if not) + * - Then '@' + * + * This prefix is derived from the value calculated using the _DT_ARGSST(arg) + * macro defined above. + */ +#define _DT_ASM_DEFINE_MACROS \ + _DT_ASM(.altmacro) \ + _DT_ASM(.macro _SST x y z) \ + _DT_ASM(.iflt \\x) \ + _DT_ASM(.ascii "-") \ + _DT_ASM(.endif) \ + _DT_ASM(.ascii "\y") \ + _DT_ASM(.ifc 8,\\z) \ + _DT_ASM(.ascii "f") \ + _DT_ASM(.endif) \ + _DT_ASM(.ascii "@") \ + _DT_ASM(.endm) \ + _DT_ASM(.macro SST x) \ + _DT_ASM(_SST \\x, %%(-(\\x*((\\x>0)-(\\x<0)))>>8), %%((\\x))&(0xff)) \ + _DT_ASM(.endm) + +#define _DT_ASM_UNDEF_MACROS \ + _DT_ASM(.purgem SST) \ + _DT_ASM(.purgem _SST) + +#define _DT_SEP_NONE +#define _DT_SEP_COMMA , + +#define _DT_ARG_TYPE(n, arg) unsigned long + +#define _DT_ASM_ARGDATA(n, arg) \ + _DT_ASM( SST %c[SST##n]) \ + _DT_ASM( .ascii _dt_s(%[VAL##n])) + +#define _DT_ASM_ARGDEF(n, arg) \ + [SST##n] "n" (_DT_ARGSST(arg)), \ + [VAL##n] _dt_s(_DT_ARG_CONSTRAINT) (arg), + +#define _DT_ASM_OUT_1(n, arg) +#define _DT_ASM_OUT_2(n, arg) "+m" (*arg) + +#define _DT_CLOBBER_1 "memory" +#define _DT_CLOBBER_2 + +#define _USDT_PROBE__(prv, prb, typ, ...) \ + do { \ + extern void __usdt##typ##_##prv##___##prb(__DT_APPLY_DEFAULT(_DT_ARG_TYPE, void, ## __VA_ARGS__)); \ + __asm__ __volatile__ (\ + _DT_ASM_DEFINE_MACROS \ + _DT_ASM(0: nop) \ + _DT_ASM( .pushsection _USDT_SECT_NAME,"?", at note) \ + _DT_ASM( .balign 4) \ + _DT_ASM( .4byte 2f-1f) \ + _DT_ASM( .4byte 4f-3f) \ + _DT_ASM( .4byte typ) \ + _DT_ASM(1: .asciz _USDT_TP_NOTE_NAME) \ + _DT_ASM(2: .balign 4) \ + _DT_ASM(3: .8byte 0b) \ + _DT_ASM( .8byte %_DT_FN_MOD[fn]) \ + _DT_ASM( .asciz _dt_s(prv)) \ + _DT_ASM( .asciz _dt_s(prb)) \ + _DT_ASM( .byte __DT_NARGS(__VA_ARGS__)) \ + __DT_APPLY_SEP(_DT_ASM_ARGDATA, _DT_ASM( .ascii " "), ## __VA_ARGS__) \ + _DT_ASM( .byte 0) \ + _DT_ASM(4: .balign 4) \ + _DT_ASM( .popsection) \ + _DT_ASM_UNDEF_MACROS \ + : __DT_APPLY(__DT_CAT(_DT_ASM_OUT_, typ), ## __VA_ARGS__) \ + : __DT_APPLY(_DT_ASM_ARGDEF, ## __VA_ARGS__) \ + [fn] _dt_s(_DT_FN_CONSTRAINT) (__func__) \ + : __DT_CAT(_DT_CLOBBER_, typ) \ + ); \ + } while (0) + +#define _USDT_PROBE_(prv, prb, typ, ...) \ + _USDT_PROBE__(prv, prb, typ, ## __VA_ARGS__) +#define _USDT_PROBE(prv, prb, ...) \ + _USDT_PROBE_(prv, prb, _USDT_TP_NOTE_TYPE, ## __VA_ARGS__) +#define _USDT_PROBE_ENABLED(prv, prb, ...) \ + _USDT_PROBE_(prv, prb, _USDT_EN_NOTE_TYPE, ## __VA_ARGS__) + +#endif /* _SYS_USDT_GENNOTE_H_ */ diff --git a/uts/common/sys/usdt_internal.h b/uts/common/sys/usdt_internal.h new file mode 100644 index 00000000..cfdb8ea2 --- /dev/null +++ b/uts/common/sys/usdt_internal.h @@ -0,0 +1,245 @@ +/* + * Hide away all the terrible macro magic. + * + * Oracle Linux DTrace. + * Copyright (c) 2016, 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. + */ + +#ifndef _LINUX_SDT_INTERNAL_H_ +#define _LINUX_SDT_INTERNAL_H_ + +/* + * This counts the number of args. + */ +#define __DT_NARGS_SEQ(dummy,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,N,...) N +#define __DT_NARGS(...) \ + __DT_NARGS_SEQ(dummy, ##__VA_ARGS__, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + +/* + * This will let macros expand before concatting them. + */ +#define __DT_PRIMITIVE_CAT(x, y) x ## y +#define __DT_CAT(x, y) __DT_PRIMITIVE_CAT(x, y) + +#define __DT_COMMA , +#define __DT_NO_COMMA +#define __DT_NONE(x) + +/* + * This will call two macros on each argument-pair passed in (the first two args + * are the names of the macros to call). Its TYPE and NAME variants will throw + * away the name and type arguments, respectively. __DT_*_APPLY_NOCOMMA + * are like DTRACE_*_APPLY, but also omit the comma between arguments in the + * expansion of the macro. DTRACE_TYPE_APPLY_DEFAULT lets you specify a default + * if no variadic args are provided. + */ +#define __DT_DOUBLE_APPLY(type_macro, arg_macro, ...) \ + __DT_CAT(__DT_DOUBLE_APPLY_, \ + __DT_NARGS(__VA_ARGS__))(type_macro, \ + arg_macro, __DT_COMMA, \ + __DT_COMMA, , ## __VA_ARGS__) +#define __DT_DOUBLE_APPLY_NOCOMMA(type_macro, arg_macro, ...) \ + __DT_CAT(__DT_DOUBLE_APPLY_, \ + __DT_NARGS(__VA_ARGS__))(type_macro, \ + arg_macro, __DT_NO_COMMA, \ + __DT_NO_COMMA, , ## __VA_ARGS__) +#define __DT_TYPE_APPLY(type_macro, ...) \ + __DT_CAT(__DT_DOUBLE_APPLY_, \ + __DT_NARGS(__VA_ARGS__))(type_macro, \ + __DT_NONE, __DT_NO_COMMA, \ + __DT_COMMA, , ## __VA_ARGS__) +#define __DT_TYPE_APPLY_NOCOMMA(type_macro, ...) \ + __DT_CAT(__DT_DOUBLE_APPLY_, \ + __DT_NARGS(__VA_ARGS__))(type_macro, \ + __DT_NONE, __DT_NO_COMMA, \ + __DT_NO_COMMA, , ## __VA_ARGS__) +#define __DT_TYPE_APPLY_DEFAULT(type_macro, def, ...) \ + __DT_CAT(__DT_DOUBLE_APPLY_, \ + __DT_NARGS(__VA_ARGS__))(type_macro, \ + __DT_NONE, __DT_NO_COMMA, \ + __DT_COMMA, def, ## __VA_ARGS__) +#define __DT_ARG_APPLY(arg_macro, ...) \ + __DT_CAT(__DT_DOUBLE_APPLY_, \ + __DT_NARGS(__VA_ARGS__))(__DT_NONE, \ + arg_macro, __DT_NO_COMMA, \ + __DT_COMMA, , ## __VA_ARGS__) +#define __DT_DOUBLE_APPLY_0(t, a, comma_t, comma_a, def) def +#define __DT_DOUBLE_APPLY_2(t, a, comma_t, comma_a, def, type1, arg1) \ + t(type1) comma_t a(arg1) +#define __DT_DOUBLE_APPLY_4(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) +#define __DT_DOUBLE_APPLY_6(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) +#define __DT_DOUBLE_APPLY_8(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) +#define __DT_DOUBLE_APPLY_10(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) +#define __DT_DOUBLE_APPLY_12(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) +#define __DT_DOUBLE_APPLY_14(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) +#define __DT_DOUBLE_APPLY_16(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) +#define __DT_DOUBLE_APPLY_18(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ + t(type9) comma_t a(arg9) +#define __DT_DOUBLE_APPLY_20(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ + t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) +#define __DT_DOUBLE_APPLY_22(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ + t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ + t(typeb) comma_t a(argb) +#define __DT_DOUBLE_APPLY_24(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ + t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ + t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) +#define __DT_DOUBLE_APPLY_26(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ + t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ + t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ + t(typed) comma_t a(argd) +#define __DT_DOUBLE_APPLY_28(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ + t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ + t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ + t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) +#define __DT_DOUBLE_APPLY_30(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ + t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ + t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ + t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ + t(typef) comma_t a(argf) +#define __DT_DOUBLE_APPLY_32(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf, typeg, argg) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ + t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ + t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ + t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ + t(typef) comma_t a(argf) comma_a t(typeg) comma_t a(argg) +#define __DT_DOUBLE_APPLY_34(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf, typeg, argg, typeh, argh) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ + t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ + t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ + t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ + t(typef) comma_t a(argf) comma_a t(typeg) comma_t a(argg) comma_a \ + t(typeh) comma_t a(argh) +#define __DT_DOUBLE_APPLY_36(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf, typeg, argg, typeh, argh, typei, argi) \ + t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ + t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ + t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ + t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ + t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ + t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ + t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ + t(typef) comma_t a(argf) comma_a t(typeg) comma_t a(argg) comma_a \ + t(typeh) comma_t a(argh) comma_a t(typei) comma_t a(argi) + +#define __DT_DOUBLE_APPLY_ERROR Error: type specified without arg. +#define __DT_DOUBLE_APPLY_1 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_3 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_5 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_7 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_9 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_11 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_13 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_15 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_17 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_19 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_21 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_23 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_25 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_27 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_29 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_31 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_33 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_35 __DT_DOUBLE_APPLY_ERROR +#define __DT_DOUBLE_APPLY_37 __DT_DOUBLE_APPLY_ERROR + +#define __DT_UINTPTR_EACH(x) uintptr_t + +#define __DT_UINTCAST_EACH(x) (uintptr_t)(x) +#define __DT_TYPE_EACH(x) ".ascii \"" __stringify(x) ",\"\n" + +/* + * Convert everything to the appropriate integral type, unless too large to fit + * into any of them, in which case its address is taken instead. + */ + +/* + * This will call macro(idx, arg, sep) for each argument passed in (idx is the + * index of the argument). + * Use __DT_APPLY(macro, ...) to generate a simple concatenation of the result + * of applying macro to each argument. + * Use __DT_APPLY_SEP(macro, sep, ...) to generate output with the result of + * applying macro to each argument separated by sep. + * Use __DT_PPLY_COMMA(macro, ...) to generate output with the result of + * applying maro to each argument separated by a comma. + */ +#define __DT_APPLY(macro, ...) __DT_CAT(__DT_APPLY_, __DT_NARGS(__VA_ARGS__))(macro, , , ## __VA_ARGS__) +#define __DT_APPLY_SEP(macro, sep, ...) __DT_CAT(__DT_APPLY_, __DT_NARGS(__VA_ARGS__))(macro, sep, , ## __VA_ARGS__) +#define __DT_APPLY_COMMA(macro, ...) __DT_CAT(__DT_APPLY_, __DT_NARGS(__VA_ARGS__))(macro, __DT_COMMA, , ## __VA_ARGS__) +#define __DT_APPLY_SEP_DEFAULT(macro, sep, def, ...) __DT_CAT(__DT_APPLY_, __DT_NARGS(__VA_ARGS__))(macro, sep, def, ## __VA_ARGS__) +#define __DT_APPLY_DEFAULT(macro, def, ...) __DT_CAT(__DT_APPLY_, __DT_NARGS(__VA_ARGS__))(macro, __DT_COMMA, def, ## __VA_ARGS__) + +#define __DT_APPLY_0(m, sep, def) def +#define __DT_APPLY_1(m, sep, def, x1) m(1, x1) +#define __DT_APPLY_2(m, sep, def, x1, x2) m(1, x1) sep m(2, x2) +#define __DT_APPLY_3(m, sep, def, x1, x2, x3) m(1, x1) sep m(2, x2) sep m(3, x3) +#define __DT_APPLY_4(m, sep, def, x1, x2, x3, x4) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) +#define __DT_APPLY_5(m, sep, def, x1, x2, x3, x4, x5) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) +#define __DT_APPLY_6(m, sep, def, x1, x2, x3, x4, x5, x6) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) +#define __DT_APPLY_7(m, sep, def, x1, x2, x3, x4, x5, x6, x7) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) +#define __DT_APPLY_8(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) +#define __DT_APPLY_9(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8, x9) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) sep m(9, x9) +#define __DT_APPLY_10(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) sep m(9, x9) sep m(10, x10) +#define __DT_APPLY_11(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) sep m(9, x9) sep m(10, x10) sep m(11, x11) +#define __DT_APPLY_12(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) sep m(9, x9) sep m(10, x10) sep m(11, x11) sep m(12, x12) +#define __DT_APPLY_13(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) sep m(9, x9) sep m(10, x10) sep m(11, x11) sep m(12, x12) sep m(13, x13) +#define __DT_APPLY_14(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) sep m(9, x9) sep m(10, x10) sep m(11, x11) sep m(12, x12) sep m(13, x13) sep m(14, x14) +#define __DT_APPLY_15(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) sep m(9, x9) sep m(10, x10) sep m(11, x11) sep m(12, x12) sep m(13, x13) sep m(14, x14) sep m(15, x15) +#define __DT_APPLY_16(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) sep m(9, x9) sep m(10, x10) sep m(11, x11) sep m(12, x12) sep m(13, x13) sep m(14, x14) sep m(15, x15) sep m(16, x16) +#define __DT_APPLY_17(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) sep m(9, x9) sep m(10, x10) sep m(11, x11) sep m(12, x12) sep m(13, x13) sep m(14, x14) sep m(15, x15) sep m(16, x16) sep m(17, x17) +#define __DT_APPLY_18(m, sep, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18) m(1, x1) sep m(2, x2) sep m(3, x3) sep m(4, x4) sep m(5, x5) sep m(6, x6) sep m(7, x7) sep m(8, x8) sep m(9, x9) sep m(10, x10) sep m(11, x11) sep m(12, x12) sep m(13, x13) sep m(14, x14) sep m(15, x15) sep m(16, x16) sep m(17, x17) sep m(18, x18) + +#endif /* _LINUX_SDT_INTERNAL_H */ -- 2.45.2 From kris.van.hees at oracle.com Sat Jun 7 14:55:20 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 07 Jun 2025 10:55:20 -0400 Subject: [DTrace-devel] [PATCH v2 14/17] usdt: implement tracing USDT probes specified in ELF notes Message-ID: Signed-off-by: Kris Van Hees --- include/dtrace/pid.h | 1 + libdtrace/dt_cg.c | 4 +- libdtrace/dt_cg.h | 3 +- libdtrace/dt_pid.c | 3 + libdtrace/dt_prov_uprobe.c | 590 +++++++++++++++++++++++++++++++++++-- 5 files changed, 573 insertions(+), 28 deletions(-) diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h index 12934500..8d4b6432 100644 --- a/include/dtrace/pid.h +++ b/include/dtrace/pid.h @@ -44,6 +44,7 @@ typedef struct pid_probespec { char *pps_xargv; /* array of xlated args */ size_t pps_xargvlen; /* (high estimate of) length of array */ int8_t *pps_argmap; /* mapped arg indexes */ + char *pps_sargv; /* list of arg sources */ /* * Fields below this point do not apply to underlying probes. diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index c68a5d45..bd0763d6 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -1597,7 +1597,7 @@ dt_cg_check_ptr_arg(dt_irlist_t *dlp, dt_regset_t *drp, dt_node_t *dnp, dt_cg_check_notnull(dlp, drp, dnp->dn_reg); } -static void dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x); +void dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x); static int dt_cg_store_val(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind, @@ -3006,7 +3006,7 @@ dt_cg_xsetx(dt_irlist_t *dlp, dt_ident_t *idp, uint_t lbl, int reg, uint64_t x) emit(dlp, instr[1]); } -static void +void dt_cg_setx(dt_irlist_t *dlp, int reg, uint64_t x) { dt_cg_xsetx(dlp, NULL, DT_LBL_NONE, reg, x); diff --git a/libdtrace/dt_cg.h b/libdtrace/dt_cg.h index fb26c125..81b79399 100644 --- a/libdtrace/dt_cg.h +++ b/libdtrace/dt_cg.h @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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. */ @@ -18,6 +18,7 @@ extern "C" { #endif extern void dt_cg(dt_pcb_t *, dt_node_t *); +extern void dt_cg_setx(dt_irlist_t *, int, uint64_t); extern void dt_cg_xsetx(dt_irlist_t *, dt_ident_t *, uint_t, int, uint64_t); extern dt_irnode_t *dt_cg_node_alloc(uint_t, struct bpf_insn); extern void dt_cg_tramp_prologue_act(dt_pcb_t *pcb, dt_activity_t act); diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index 9b1a2278..d12b7919 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -1077,6 +1077,9 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr, if (argmap) psp.pps_argmap = argmap; + if (tp->tracepoint.args[0] != 0) + psp.pps_sargv = tp->tracepoint.args; + dt_dprintf("providing %s:%s:%s:%s for pid %d\n", psp.pps_prv, psp.pps_mod, psp.pps_fun, psp.pps_prb, psp.pps_pid); if (pvp->impl->provide_probe(dtp, &psp) < 0) { diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index 28762eb3..cf5cfd43 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -46,6 +46,231 @@ /* Provider name for the underlying probes. */ static const char prvname[] = "uprobe"; +typedef struct asm_reg { + const char *name; /* register name */ + const char *mname; /* *pt_regs member name */ + size_t moff; /* offset in member */ + uint64_t mask; /* value mask (after shift) */ + uint8_t shift; /* value shift */ + int off; /* *pt_regs value offset */ + dt_hentry_t he; +} asm_reg_t; + +static uint32_t +reg_hval(const asm_reg_t *reg) +{ + return str2hval(reg->name, 0); +} + +static int +reg_cmp(const asm_reg_t *p, const asm_reg_t *q) +{ + return strcmp(p->name, q->name); +} + +DEFINE_HE_STD_LINK_FUNCS(reg, asm_reg_t, he) +DEFINE_HTAB_STD_OPS(reg) + +static asm_reg_t asm_regs[] = { +#if defined(__amd64) +# define REG_R(n, m) { (n), (m), 0, (-1LL), 0, 0, } +# define REG_E(n, m) { (n), (m), 0, ((1ULL << 32) - 1), 0, 0, } +# define REG_X(n, m) { (n), (m), 0, ((1ULL << 16) - 1), 0, 0, } +# define REG_L(n, m) { (n), (m), 0, ((1ULL << 8) - 1), 0, 0, } +# define REG_H(n, m) { (n), (m), 0, ((1ULL << 8) - 1), 8, 0, } + + REG_R("rax", "ax"), + REG_E("eax", "ax"), + REG_X("ax", "ax"), + REG_L("al", "ax"), + REG_H("ah", "ax"), + REG_R("rbx", "bx"), + REG_E("ebx", "bx"), + REG_X("bx", "bx"), + REG_L("bl", "bx"), + REG_H("bh", "bx"), + REG_R("rcx", "cx"), + REG_E("ecx", "cx"), + REG_X("cx", "cx"), + REG_L("cl", "cx"), + REG_H("ch", "cx"), + REG_R("rdx", "dx"), + REG_E("edx", "dx"), + REG_X("dx", "dx"), + REG_L("dl", "dx"), + REG_H("dh", "dx"), + + REG_R("rsi", "si"), + REG_E("esi", "si"), + REG_X("si", "si"), + REG_L("sil", "si"), + REG_R("rdi", "di"), + REG_E("edi", "di"), + REG_X("di", "di"), + REG_L("dil", "di"), + REG_R("rsp", "sp"), + REG_E("esp", "sp"), + REG_X("sp", "sp"), + REG_L("spl", "sp"), + REG_R("rbp", "bp"), + REG_E("ebp", "bp"), + REG_X("bp", "bp"), + REG_L("bpl", "bp"), + + REG_R("r8", "r8"), + REG_E("r8d", "r8"), + REG_X("r8w", "r8"), + REG_L("r8b", "r8"), + REG_R("r9", "r9"), + REG_E("r9d", "r9"), + REG_X("r9w", "r9"), + REG_L("r9b", "r9"), + REG_R("r10", "r10"), + REG_E("r10d", "r10"), + REG_X("r10w", "r10"), + REG_L("r10b", "r10"), + REG_R("r11", "r11"), + REG_E("r11d", "r11"), + REG_X("r11w", "r11"), + REG_L("r11b", "r11"), + REG_R("r12", "r12"), + REG_E("r12d", "r12"), + REG_X("r12w", "r12"), + REG_L("r12b", "r12"), + REG_R("r13", "r13"), + REG_E("r13d", "r13"), + REG_X("r13w", "r13"), + REG_L("r13b", "r13"), + REG_R("r14", "r14"), + REG_E("r14d", "r14"), + REG_X("r14w", "r14"), + REG_L("r14b", "r14"), + REG_R("r15", "r15"), + REG_E("r15d", "r15"), + REG_X("r15w", "r15"), + REG_L("r15b", "r15"), + + REG_R("rip", "ip"), + REG_E("eip", "ip"), + REG_X("ip", "ip"), +#elif defined(__aarch64__) +# define REG_X(n, m, i) { (n), (m), (i) * sizeof(uint64_t), (-1LL), 0, 0, } +# define REG_W(n, m, i) { (n), (m), (i) * sizeof(uint64_t), ((1ULL << 32) - 1), 0, 0, } + + REG_X("x0", "regs", 0), + REG_X("x1", "regs", 1), + REG_X("x2", "regs", 2), + REG_X("x3", "regs", 3), + REG_X("x4", "regs", 4), + REG_X("x5", "regs", 5), + REG_X("x6", "regs", 6), + REG_X("x7", "regs", 7), + REG_X("x8", "regs", 8), + REG_X("x9", "regs", 9), + REG_X("x10", "regs", 10), + REG_X("x11", "regs", 11), + REG_X("x12", "regs", 12), + REG_X("x13", "regs", 13), + REG_X("x14", "regs", 14), + REG_X("x15", "regs", 15), + REG_X("x16", "regs", 16), + REG_X("x17", "regs", 17), + REG_X("x18", "regs", 18), + REG_X("x19", "regs", 19), + REG_X("x20", "regs", 20), + REG_X("x21", "regs", 21), + REG_X("x22", "regs", 22), + REG_X("x23", "regs", 23), + REG_X("x24", "regs", 24), + REG_X("x25", "regs", 25), + REG_X("x26", "regs", 26), + REG_X("x27", "regs", 27), + REG_X("x28", "regs", 28), + REG_X("x29", "regs", 29), + REG_X("x30", "regs", 30), + + REG_W("w0", "regs", 0), + REG_W("w1", "regs", 1), + REG_W("w2", "regs", 2), + REG_W("w3", "regs", 3), + REG_W("w4", "regs", 4), + REG_W("w5", "regs", 5), + REG_W("w6", "regs", 6), + REG_W("w7", "regs", 7), + REG_W("w8", "regs", 8), + REG_W("w9", "regs", 9), + REG_W("w10", "regs", 10), + REG_W("w11", "regs", 11), + REG_W("w12", "regs", 12), + REG_W("w13", "regs", 13), + REG_W("w14", "regs", 14), + REG_W("w15", "regs", 15), + REG_W("w16", "regs", 16), + REG_W("w17", "regs", 17), + REG_W("w18", "regs", 18), + REG_W("w19", "regs", 19), + REG_W("w20", "regs", 20), + REG_W("w21", "regs", 21), + REG_W("w22", "regs", 22), + REG_W("w23", "regs", 23), + REG_W("w24", "regs", 24), + REG_W("w25", "regs", 25), + REG_W("w26", "regs", 26), + REG_W("w27", "regs", 27), + REG_W("w28", "regs", 28), + REG_W("w29", "regs", 29), + REG_W("w30", "regs", 30), + + REG_X("sp", "sp", 0), + REG_X("pc", "sp", 0), + + REG_X("lr", "regs", 30), +#else +# error ISA not supported +#endif +}; + +static asm_reg_t * +get_asm_reg(dt_provider_t *pvp, const char *name) +{ + dt_htab_t *rtab = pvp->prv_data; + asm_reg_t regt; + + if (rtab == NULL) { + int i; + asm_reg_t *rp, *reg = NULL; + + rtab = dt_htab_create(®_htab_ops); + if (rtab == NULL) + return NULL; + + pvp->prv_data = rtab; + + for (i = 0, rp = asm_regs; i < ARRAY_SIZE(asm_regs); + i++, rp++) { +#if defined(__amd64) + rp->off = dt_cg_ctf_offsetof("struct pt_regs", + rp->mname, NULL, 0) + + rp->moff; +#elif defined(__aarch64__) + rp->off = dt_cg_ctf_offsetof("struct user_pt_regs", + rp->mname, NULL, 0) + + rp->moff; +#endif + + if (dt_htab_insert(rtab, rp) < 0) + return NULL; + if (strcmp(rp->name, name) == 0) + reg = rp; + } + + return reg; + } + + regt.name = name; + return dt_htab_lookup(rtab, ®t); +} + #define PP_IS_RETURN 0x1 #define PP_IS_FUNCALL 0x2 #define PP_IS_ENABLED 0x4 @@ -55,15 +280,17 @@ static const char prvname[] = "uprobe"; typedef struct dt_uprobe { dev_t dev; ino_t inum; - char *fn; /* object full file name */ - char *func; /* function */ + char *fn; /* object full file name */ + char *func; /* function */ uint64_t off; int flags; tp_probe_t *tp; - int argc; /* number of args */ - dt_argdesc_t *args; /* args array (points into argvbuf) */ - char *argvbuf; /* arg strtab */ - dt_list_t probes; /* pid/USDT probes triggered by it */ + int argc; /* number of args */ + dt_argdesc_t *args; /* args array (points into argvbuf) */ + char *argvbuf; /* arg strtab */ + int sargc; /* number of arg source specs */ + char *sargv; /* arg source specs */ + dt_list_t probes; /* pid/USDT probes triggered by it */ } dt_uprobe_t; typedef struct list_probe { @@ -132,6 +359,7 @@ static void probe_destroy_underlying(dtrace_hdl_t *dtp, void *datap) dt_free(dtp, upp->func); dt_free(dtp, upp->args); dt_free(dtp, upp->argvbuf); + dt_free(dtp, upp->sargv); dt_free(dtp, upp); } @@ -290,15 +518,19 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp) * status in the clause flags for dt_stmts[n]. */ if (dt_stmt_clsflag_test(stp, DT_CLSFLAG_USDT_INCLUDE | DT_CLSFLAG_USDT_EXCLUDE) == 0) { - char lastchar = pdp->prv[strlen(pdp->prv) - 1]; + size_t len = strlen(pdp->prv); /* * If the last char in the provider description is * neither '*' nor a digit, it cannot be a USDT probe. */ - if (lastchar != '*' && !isdigit(lastchar)) { - dt_stmt_clsflag_set(stp, DT_CLSFLAG_USDT_EXCLUDE); - return 1; + if (len > 1) { + char lastchar = pdp->prv[len - 1]; + + if (lastchar != '*' && !isdigit(lastchar)) { + dt_stmt_clsflag_set(stp, DT_CLSFLAG_USDT_EXCLUDE); + return 1; + } } /* @@ -340,6 +572,17 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp) return 0; } +static void usdt_error(dt_pcb_t *pcb, const char *fmt, ...) +{ + dtrace_hdl_t *dtp = pcb->pcb_hdl; + va_list ap; + + va_start(ap, fmt); + dt_set_errmsg(dtp, NULL, NULL, NULL, 0, fmt, ap); + va_end(ap); + longjmp(pcb->pcb_jmpbuf, EDT_COMPILER); +} + static int add_probe_uprobe(dtrace_hdl_t *dtp, dt_probe_t *prp) { dtrace_difo_t *dp; @@ -539,6 +782,18 @@ static int populate_args(dtrace_hdl_t *dtp, const pid_probespec_t *psp, upp->argc = psp->pps_xargc; + /* Copy argument value source string data (if any). */ + if (psp->pps_sargv) { + /* + * Is-enabled probes have one (internal use only) argument. + * They retain the narg/xarg data from the probe they are + * associated with, for consistency, but that data will not be + * used. + */ + upp->sargc = (upp->flags & PP_IS_ENABLED) ? 1 : psp->pps_nargc; + upp->sargv = strdup(psp->pps_sargv); + } + /* * If we have a nonzero number of args, we always have at least one narg * and at least one xarg. Double-check to be sure. (These are not @@ -700,9 +955,6 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, assert(strcmp(upp->func, psp->pps_fun) == 0); } - if (populate_args(dtp, psp, upp) < 0) - goto fail; - switch (psp->pps_type) { case DTPPT_RETURN: upp->flags |= PP_IS_RETURN; @@ -719,6 +971,9 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, */ } + if (populate_args(dtp, psp, upp) < 0) + goto fail; + return uprp; fail: @@ -889,6 +1144,289 @@ static void enable_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp) enable(dtp, prp, 1); } +/* + * Generate code that populates the probe arguments. + */ +static void copy_args(dt_pcb_t *pcb, const dt_uprobe_t *upp) +{ + dtrace_hdl_t *dtp = pcb->pcb_hdl; + dt_irlist_t *dlp = &pcb->pcb_ir; + dt_provider_t *pvp = dt_provider_lookup(dtp, dt_usdt.name); + asm_reg_t *areg; + int i; + char *p = upp->sargv; + + assert(pvp != NULL); + + for (i = 0; i < upp->sargc; i++) { + int ssize, disp, len; + char *reg = NULL; + int64_t val = 0; + + /* + * Get sign/size. Missing sign/size is an error. + * Also, float is not supported. + */ + ssize = 0; + len = -1; + if (sscanf(p, " %d @ %n", &ssize, &len) <= 0 || len == -1) + usdt_error(pcb, "Missing sign/size in arg%d spec", i); + + p += len; + + /* Look for dereference (with optional displacement). */ + disp = 0; + len = -1; +#ifdef __aarch64__ + if (sscanf(p, "[ %m[^],] %n", ®, &len) > 0 && len > 0) { + char *ireg = NULL; + + p += len; + + if (*p != ']') { + /* Expect a displacement or index register. */ + if (sscanf(p, ", %n", &len) < 0) + usdt_error(pcb, "Expected , in arg%d spec", i); + + p += len; + + if (sscanf(p, "%d ] %n", &disp, &len) != 1 && + sscanf(p, "%m[^],] , %d ] %n", &ireg, &disp, + &len) != 2 && + sscanf(p, "%m[^]] ] %n", &ireg, &len) != 1) + usdt_error(pcb, "Missing displacement and/or index register in arg%d spec", i); + } else + sscanf(p, "] %n", &len); + + p += len; + + /* + * If there is an index register, put its value in %r1 + * (after applying the scale if specified). + */ + if (ireg != NULL) { + areg = get_asm_reg(pvp, ireg); + if (areg == NULL) + usdt_error(pcb, "Unknown index register %s in arg%d spec", ireg, i); + + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, areg->off)); + } + + /* If there is a base register, get its value. */ + if (reg != NULL) { + int neg = 0; + int shift; + + if (ssize < 0) { + neg = 1; + ssize = -ssize; + } + + shift = 64 - ssize * 8; + + areg = get_asm_reg(pvp, reg); + if (areg == NULL) + usdt_error(pcb, "Unknown base register %s in arg%d spec", reg, i); + + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, areg->off)); + + if (ireg != NULL) + emit(dlp, BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1)); + + if (disp != 0) + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, disp)); + + /* Load value from the pointer. */ + 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, ssize)); + emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user])); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(i))); + if (shift) { + emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift)); + emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift)); + } + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + } else { + if (disp != 0) + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, disp)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_1)); + } + + free(reg); + free(ireg); + } else if (sscanf(p, "%ld %n", &val, &len) > 0) { + /* Handle constant value. */ + p += len; + + if (val > (1ULL << 32) - 1ULL) { + dt_cg_setx(dlp, BPF_REG_0, val); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + } else + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), val)); + } else if (sscanf(p, "%m[a-z0-9] %n", ®, &len) > 0) { + /* Handle simple register. */ + int neg = 0; + int shift; + uint_t sz; + + if (ssize < 0) { + neg = 1; + ssize = -ssize; + } + + shift = 64 - ssize * 8; + sz = bpf_ldst_size(ssize, 1); + + areg = get_asm_reg(pvp, reg); + if (areg == NULL) + usdt_error(pcb, "Unknown register %s in arg%d spec", reg, i); + + emit(dlp, BPF_LOAD(sz, BPF_REG_0, BPF_REG_8, areg->off)); + if (shift) { + emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift)); + emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift)); + } + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + + free(reg); + p += len; + } else + usdt_error(pcb, "Unknown format in arg%d spec", i); +#else + if ((sscanf(p, "%d ( %n", &disp, &len) == 1 || + sscanf(p, "( %n", &len) == 0) && len >= 0) { + char *ireg = NULL; + int scale = -1; + + p += len; + + if (*p != ',') { + /* Expect a base register. */ + if (sscanf(p, "%%%m[^,)] %n", ®, &len) <= 0) + usdt_error(pcb, "Missing base register in arg%d spec", i); + + p += len; + } + + if (*p != ')') { + /* Expect an index register. */ + if (sscanf(p, ", %%%m[^,)] %n", &ireg, &len) <= 0) + usdt_error(pcb, "Missing index register in arg%d spec", i); + + p += len; + + /* Expect scale or closing parenthesis. */ + len = 0; + if (sscanf(p, ", %d ) %n", &scale, &len) <= 0 && + sscanf(p, ") %n", &len) < 0) + usdt_error(pcb, "Missing scale or ) in arg%d spec", i); + } else + sscanf(p, ") %n", &len); + + p += len; + + /* + * If there is an index register, put its value in %r1 + * (after applying the scale if specified). + */ + if (ireg != NULL) { + areg = get_asm_reg(pvp, ireg); + if (areg == NULL) + usdt_error(pcb, "Unknown index register %s in arg%d spec", ireg, i); + + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, areg->off)); + if (scale > 0) + emit(dlp, BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, scale)); + } + + /* If there is a base register, get its value. */ + if (reg != NULL) { + int neg = 0; + int shift; + + if (ssize < 0) { + neg = 1; + ssize = -ssize; + } + + shift = 64 - ssize * 8; + + areg = get_asm_reg(pvp, reg); + if (areg == NULL) + usdt_error(pcb, "Unknown base register %s in arg%d spec", reg, i); + + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_8, areg->off)); + + if (ireg != NULL) + emit(dlp, BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1)); + + if (disp != 0) + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, disp)); + + /* Load value from the pointer. */ + 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, ssize)); + emit(dlp, BPF_MOV_REG(BPF_REG_3, BPF_REG_0)); + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_user])); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_7, DMST_ARG(i))); + if (shift) { + emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift)); + emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift)); + } + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + } else { + if (disp != 0) + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, disp)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_1)); + } + + free(reg); + free(ireg); + } else if (sscanf(p, "%%%ms %n", ®, &len) > 0) { + /* Handle simple register. */ + int neg = 0; + int shift; + uint_t sz; + + if (ssize < 0) { + neg = 1; + ssize = -ssize; + } + + shift = 64 - ssize * 8; + sz = bpf_ldst_size(ssize, 1); + + areg = get_asm_reg(pvp, reg); + if (areg == NULL) + usdt_error(pcb, "Unknown register %s in arg%d spec", reg, i); + + emit(dlp, BPF_LOAD(sz, BPF_REG_0, BPF_REG_8, areg->off)); + if (shift) { + emit(dlp, BPF_ALU64_IMM(BPF_LSH, BPF_REG_0, shift)); + emit(dlp, BPF_ALU64_IMM(neg ? BPF_ARSH : BPF_RSH, BPF_REG_0, shift)); + } + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + + free(reg); + p += len; + } else if (sscanf(p, "$%ld %n", &val, &len) > 0) { + /* Handle constant value. */ + p += len; + + if (val > (1ULL << 32) - 1ULL) { + dt_cg_setx(dlp, BPF_REG_0, val); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(i), BPF_REG_0)); + } else + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(i), val)); + } else + usdt_error(pcb, "Unknown format in arg%d spec", i); +#endif + } +} + /* * Generate a BPF trampoline for a pid or USDT probe. * @@ -981,17 +1519,10 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) if (upp->flags & PP_IS_RETURN) goto out; - dt_cg_tramp_copy_args_from_regs(pcb, 0); - - /* - * Apply arg mappings, if needed. - */ - if (upp->flags & PP_IS_MAPPED) { - - /* dt_cg_tramp_map_args() works from the saved args. */ - dt_cg_tramp_save_args(pcb); - dt_cg_tramp_map_args(pcb, upp->args, upp->argc); - } + if (upp->sargc) + copy_args(pcb, upp); + else + dt_cg_tramp_copy_args_from_regs(pcb, 0); /* * Retrieve the PID of the process that caused the probe to fire. @@ -1022,7 +1553,7 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) * The trampoline writes 1 into the location pointed to by the passed-in arg. */ emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_FP, DT_TRAMP_SP_SLOT(0), 1)); - emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_8, PT_REGS_ARG0)); + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(0))); emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_FP)); emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_TRAMP_SP_SLOT(0))); emit(dlp, BPF_MOV_IMM(BPF_REG_3, sizeof(uint32_t))); @@ -1042,6 +1573,15 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) /* Read the bit mask from the table lookup in %r6. */ // FIXME someday, extend this past 64 bits emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_0, offsetof(usdt_prids_map_val_t, mask))); + /* + * Apply arg mappings, if needed. + */ + if (upp->flags & PP_IS_MAPPED) { + /* dt_cg_tramp_map_args() works from the saved args. */ + dt_cg_tramp_save_args(pcb); + dt_cg_tramp_map_args(pcb, upp->args, upp->argc); + } + /* * Hold the bit mask in %r6 between clause calls. */ -- 2.45.2 From noreply at github.com Sat Jun 7 15:01:14 2025 From: noreply at github.com (euloh) Date: Sat, 07 Jun 2025 08:01:14 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] df960f: usdt: implement tracing USDT probes specified in E... Message-ID: Branch: refs/heads/kvh/usdt-dev Home: https://github.com/oracle/dtrace-utils Commit: df960fff50078e5516f4d5191f975f006f7a0a4f https://github.com/oracle/dtrace-utils/commit/df960fff50078e5516f4d5191f975f006f7a0a4f Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M include/dtrace/pid.h M libdtrace/dt_cg.c M libdtrace/dt_cg.h M libdtrace/dt_pid.c M libdtrace/dt_prov_uprobe.c Log Message: ----------- usdt: implement tracing USDT probes specified in ELF notes Signed-off-by: Kris Van Hees Commit: be2ab3046d24c23d8eef61f6e51505fc69b717e5 https://github.com/oracle/dtrace-utils/commit/be2ab3046d24c23d8eef61f6e51505fc69b717e5 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libdtrace/drti.c M libdtrace/dt_dof.c M libdtrace/dt_impl.h M libdtrace/dt_link.c M libdtrace/dt_program.c M test/triggers/Build A test/triggers/usdt-tst-arg-const-prov.d A test/triggers/usdt-tst-arg-const.c A test/triggers/usdt-tst-arg-reg-prov.d A test/triggers/usdt-tst-arg-reg.c A test/triggers/usdt-tst-deref-decode-prov.d A test/triggers/usdt-tst-deref-decode.aarch64.c A test/triggers/usdt-tst-deref-decode.x86_64.c M test/unittest/options/tst.strip.sh A test/unittest/usdt/err.wrong-probe-argc-cc.sh A test/unittest/usdt/err.wrong-probe-argc-rt.sh A test/unittest/usdt/err.wrong-probe.sh A test/unittest/usdt/err.wrong-prov.sh A test/unittest/usdt/tst.arg-reg.d A test/unittest/usdt/tst.arg-reg.r R test/unittest/usdt/tst.badguess.sh R test/unittest/usdt/tst.badguess.x A test/unittest/usdt/tst.const.d A test/unittest/usdt/tst.const.r A test/unittest/usdt/tst.deref-decode.d R test/unittest/usdt/tst.guess32.sh R test/unittest/usdt/tst.guess32.x M test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p M test/utils/Build M test/utils/showUSDT.c M uts/common/sys/sdt.h A uts/common/sys/usdt.h A uts/common/sys/usdt_gennote.h A uts/common/sys/usdt_internal.h Log Message: ----------- link: implement USDT probe definitions in ELF notes Signed-off-by: Kris Van Hees Commit: 352ee3bc356189b4e9eb3cca63645f7f9ca8ad52 https://github.com/oracle/dtrace-utils/commit/352ee3bc356189b4e9eb3cca63645f7f9ca8ad52 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh Log Message: ----------- test: fix test for non-installed testing On a system without DTrace installed, cannot be found, causing this test to fail. Use test_cppflags to ensure the correct location is used in all cases. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 4258ce213541547b85bbf998c3208e385c010aed https://github.com/oracle/dtrace-utils/commit/4258ce213541547b85bbf998c3208e385c010aed Author: Eugene Loh Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M test/unittest/usdt/tst.pidprobes.sh Log Message: ----------- test: Adapt USDT PC search for USDT LTO changes To check USDT PCs, we looked at disassembly for characteristics that indicated USDT probes. With LTO, however, USDT instrumentation has changed. Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. Note that tst.pidargs.sh and tst.pidargmap.sh depend on tst.pidprobes.sh. Therefore, those tests also benefit from this change. They do not yet pass, however, since index 0 for args[] is said to be out of range. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/d1df03dc53af...4258ce213541 To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From nick.alcock at oracle.com Sat Jun 7 18:46:55 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Sat, 07 Jun 2025 19:46:55 +0100 Subject: [DTrace-devel] [PATCH 14/17] usdt: implement tracing USDT probes specified in ELF notes In-Reply-To: (Kris Van Hees's message of "Sat, 07 Jun 2025 02:15:05 -0400") References: Message-ID: <87msajjso0.fsf@esperi.org.uk> On 7 Jun 2025, Kris Van Hees said: > --- > include/dtrace/pid.h | 1 + > libdtrace/dt_cg.c | 4 +- > libdtrace/dt_cg.h | 3 +- > libdtrace/dt_pid.c | 3 + > libdtrace/dt_prov_uprobe.c | 590 +++++++++++++++++++++++++++++++++++-- > 5 files changed, 573 insertions(+), 28 deletions(-) Reviewed-by: Nick Alcock (though I already have changes planned, heh heh -- but this will do for this release, and about 90% of it survives those changes anyway: it just moves around a bit.) From nick.alcock at oracle.com Sat Jun 7 18:47:38 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Sat, 07 Jun 2025 19:47:38 +0100 Subject: [DTrace-devel] [PATCH 15/17] link: implement USDT probe definitions in ELF notes In-Reply-To: (Kris Van Hees via DTrace-devel's message of "Sat, 07 Jun 2025 02:15:06 -0400") References: Message-ID: <87ikl7jsmt.fsf@esperi.org.uk> On 7 Jun 2025, Kris Van Hees via DTrace-devel stated: > Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock -- NULL && (void) From nick.alcock at oracle.com Sat Jun 7 18:49:29 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Sat, 07 Jun 2025 19:49:29 +0100 Subject: [DTrace-devel] [PATCH 13/17] dtprobed, usdt parser: add support for ELF notes-based USDT In-Reply-To: (Kris Van Hees's message of "Sat, 07 Jun 2025 02:15:04 -0400") References: Message-ID: <87ecvvjsjq.fsf@esperi.org.uk> On 7 Jun 2025, Kris Van Hees verbalised: > Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock modulo this piece of utter pedantry: > + * rc = 1: All blocks written successfully. > + * rc = 0: Some blocks not written. > + * rc = -1: An erorr happened (some blocks not written). Erorr is an erorr! > + if (prp->fun != NULL) { > + ptp->next = prp->next; > + ptp->nargc = prp->nargc; > + ptp->nargs = prp->nargs; > + ptp->nargsz = prp->nargsz; > + ptp->xargc = prp->xargc; > + ptp->xargs = prp->xargs; > + ptp->xargsz = prp->xargsz; > + ptp->xmap = prp->xmap; > + prp->next = ptp; > + prp->ntp++; > + } else { > + dt_htab_delete(prbmap, ptp); > + dt_htab_insert(pvp->pmap, ptp); > + ptp->ntp = 1; > + ptp->nargc = prp->nargc; > + ptp->nargs = prp->nargs; > + ptp->nargsz = prp->nargsz; > + ptp->xargc = prp->xargc; > + ptp->xargs = prp->xargs; > + ptp->xargsz = prp->xargsz; > + ptp->xmap = prp->xmap; > + pvp->probec++; > + } > + } > + > +prvit = NULL; > +while ((pvp = dt_htab_next(prvmap, &prvit)) != NULL) { > + dt_htab_next_t *prbit = NULL; > + dt_probe_t *prp; > + > + dt_dbg_usdt(" Provider '%s' with %d probe%s:\n", pvp->name, pvp->probec, pvp->probec == 1 ? "" : "s"); > + while ((prp = dt_htab_next(pvp->pmap, &prbit)) != NULL) { > + dt_dbg_usdt(" Probe %s:%s:%s:%s (off %x)\n", prp->prv, prp->mod, prp->fun ? prp->fun : "", prp->prb, prp->fun ? prp->off : -1); > + while ((prp = prp->next) != NULL) > + dt_dbg_usdt(" Probe %s:%s:%s:%s (off %x)\n", prp->prv, prp->mod, prp->fun ? prp->fun : "", prp->prb, prp->fun ? prp->off : -1); > + } > +} > + > + /* Emit any provider that has tracepoints. */ > + prvit = NULL; > + while ((pvp = dt_htab_next(prvmap, &prvit)) != NULL) { > + if (pvp->probec > 0 && emit_provider(out, dhp, pvp) == -1) > + goto err; > + } > + > + goto out; Going by the indentation, the outdented bit looks like debugging code you either forgot to remove, or forgot to reindent :) -- NULL && (void) From kris.van.hees at oracle.com Sat Jun 7 23:44:48 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 7 Jun 2025 19:44:48 -0400 Subject: [DTrace-devel] [PATCH 13/17] dtprobed, usdt parser: add support for ELF notes-based USDT In-Reply-To: <87ecvvjsjq.fsf@esperi.org.uk> References: <87ecvvjsjq.fsf@esperi.org.uk> Message-ID: On Sat, Jun 07, 2025 at 07:49:29PM +0100, Nick Alcock wrote: > On 7 Jun 2025, Kris Van Hees verbalised: > > > Signed-off-by: Kris Van Hees > > Reviewed-by: Nick Alcock Thanks. > Modulo this piece of utter pedantry: > > > + * rc = 1: All blocks written successfully. > > + * rc = 0: Some blocks not written. > > + * rc = -1: An erorr happened (some blocks not written). > > Erorr is an erorr! Thanks. > > + if (prp->fun != NULL) { > > + ptp->next = prp->next; > > + ptp->nargc = prp->nargc; > > + ptp->nargs = prp->nargs; > > + ptp->nargsz = prp->nargsz; > > + ptp->xargc = prp->xargc; > > + ptp->xargs = prp->xargs; > > + ptp->xargsz = prp->xargsz; > > + ptp->xmap = prp->xmap; > > + prp->next = ptp; > > + prp->ntp++; > > + } else { > > + dt_htab_delete(prbmap, ptp); > > + dt_htab_insert(pvp->pmap, ptp); > > + ptp->ntp = 1; > > + ptp->nargc = prp->nargc; > > + ptp->nargs = prp->nargs; > > + ptp->nargsz = prp->nargsz; > > + ptp->xargc = prp->xargc; > > + ptp->xargs = prp->xargs; > > + ptp->xargsz = prp->xargsz; > > + ptp->xmap = prp->xmap; > > + pvp->probec++; > > + } > > + } > > + > > +prvit = NULL; > > +while ((pvp = dt_htab_next(prvmap, &prvit)) != NULL) { > > + dt_htab_next_t *prbit = NULL; > > + dt_probe_t *prp; > > + > > + dt_dbg_usdt(" Provider '%s' with %d probe%s:\n", pvp->name, pvp->probec, pvp->probec == 1 ? "" : "s"); > > + while ((prp = dt_htab_next(pvp->pmap, &prbit)) != NULL) { > > + dt_dbg_usdt(" Probe %s:%s:%s:%s (off %x)\n", prp->prv, prp->mod, prp->fun ? prp->fun : "", prp->prb, prp->fun ? prp->off : -1); > > + while ((prp = prp->next) != NULL) > > + dt_dbg_usdt(" Probe %s:%s:%s:%s (off %x)\n", prp->prv, prp->mod, prp->fun ? prp->fun : "", prp->prb, prp->fun ? prp->off : -1); > > + } > > +} > > + > > + /* Emit any provider that has tracepoints. */ > > + prvit = NULL; > > + while ((pvp = dt_htab_next(prvmap, &prvit)) != NULL) { > > + if (pvp->probec > 0 && emit_provider(out, dhp, pvp) == -1) > > + goto err; > > + } > > + > > + goto out; > > Going by the indentation, the outdented bit looks like debugging code > you either forgot to remove, or forgot to reindent :) Ah yes, thanks. From kris.van.hees at oracle.com Sat Jun 7 23:45:10 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 7 Jun 2025 19:45:10 -0400 Subject: [DTrace-devel] [PATCH 14/17] usdt: implement tracing USDT probes specified in ELF notes In-Reply-To: <87msajjso0.fsf@esperi.org.uk> References: <87msajjso0.fsf@esperi.org.uk> Message-ID: On Sat, Jun 07, 2025 at 07:46:55PM +0100, Nick Alcock wrote: > On 7 Jun 2025, Kris Van Hees said: > > > --- > > include/dtrace/pid.h | 1 + > > libdtrace/dt_cg.c | 4 +- > > libdtrace/dt_cg.h | 3 +- > > libdtrace/dt_pid.c | 3 + > > libdtrace/dt_prov_uprobe.c | 590 +++++++++++++++++++++++++++++++++++-- > > 5 files changed, 573 insertions(+), 28 deletions(-) > > Reviewed-by: Nick Alcock Thanks. From kris.van.hees at oracle.com Sat Jun 7 23:45:26 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 7 Jun 2025 19:45:26 -0400 Subject: [DTrace-devel] [PATCH 15/17] link: implement USDT probe definitions in ELF notes In-Reply-To: <87ikl7jsmt.fsf@esperi.org.uk> References: <87ikl7jsmt.fsf@esperi.org.uk> Message-ID: On Sat, Jun 07, 2025 at 07:47:38PM +0100, Nick Alcock wrote: > On 7 Jun 2025, Kris Van Hees via DTrace-devel stated: > > > Signed-off-by: Kris Van Hees > > Reviewed-by: Nick Alcock Thanks. From noreply at github.com Sat Jun 7 23:50:03 2025 From: noreply at github.com (euloh) Date: Sat, 07 Jun 2025 16:50:03 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] b7d538: dtprobed, usdt parser: add support for ELF notes-b... Message-ID: Branch: refs/heads/kvh/usdt-dev Home: https://github.com/oracle/dtrace-utils Commit: b7d53876071e1a600c3b2725f486e64fd72d2507 https://github.com/oracle/dtrace-utils/commit/b7d53876071e1a600c3b2725f486e64fd72d2507 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dof_stash.c M dtprobed/dof_stash.h M dtprobed/dtprobed.c M libcommon/Build M libcommon/usdt_parser.c M libcommon/usdt_parser.h M libcommon/usdt_parser_dof.c M libcommon/usdt_parser_host.c A libcommon/usdt_parser_notes.c A uts/common/sys/usdt_note_defs.h Log Message: ----------- dtprobed, usdt parser: add support for ELF notes-based USDT Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: ee8f0d96e441a417a40254d50fec4ba92f7cdfbd https://github.com/oracle/dtrace-utils/commit/ee8f0d96e441a417a40254d50fec4ba92f7cdfbd Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M include/dtrace/pid.h M libdtrace/dt_cg.c M libdtrace/dt_cg.h M libdtrace/dt_pid.c M libdtrace/dt_prov_uprobe.c Log Message: ----------- usdt: implement tracing USDT probes specified in ELF notes Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 11d545fa81f9047c730e61f79bf695eaa163f8cf https://github.com/oracle/dtrace-utils/commit/11d545fa81f9047c730e61f79bf695eaa163f8cf Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libdtrace/drti.c M libdtrace/dt_dof.c M libdtrace/dt_impl.h M libdtrace/dt_link.c M libdtrace/dt_program.c M test/triggers/Build A test/triggers/usdt-tst-arg-const-prov.d A test/triggers/usdt-tst-arg-const.c A test/triggers/usdt-tst-arg-reg-prov.d A test/triggers/usdt-tst-arg-reg.c A test/triggers/usdt-tst-deref-decode-prov.d A test/triggers/usdt-tst-deref-decode.aarch64.c A test/triggers/usdt-tst-deref-decode.x86_64.c M test/unittest/options/tst.strip.sh A test/unittest/usdt/err.wrong-probe-argc-cc.sh A test/unittest/usdt/err.wrong-probe-argc-rt.sh A test/unittest/usdt/err.wrong-probe.sh A test/unittest/usdt/err.wrong-prov.sh A test/unittest/usdt/tst.arg-reg.d A test/unittest/usdt/tst.arg-reg.r R test/unittest/usdt/tst.badguess.sh R test/unittest/usdt/tst.badguess.x A test/unittest/usdt/tst.const.d A test/unittest/usdt/tst.const.r A test/unittest/usdt/tst.deref-decode.d R test/unittest/usdt/tst.guess32.sh R test/unittest/usdt/tst.guess32.x M test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p M test/utils/Build M test/utils/showUSDT.c M uts/common/sys/sdt.h A uts/common/sys/usdt.h A uts/common/sys/usdt_gennote.h A uts/common/sys/usdt_internal.h Log Message: ----------- link: implement USDT probe definitions in ELF notes Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 455d7d4589472a9a135350841b1a036eeeda8db8 https://github.com/oracle/dtrace-utils/commit/455d7d4589472a9a135350841b1a036eeeda8db8 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh Log Message: ----------- test: fix test for non-installed testing On a system without DTrace installed, cannot be found, causing this test to fail. Use test_cppflags to ensure the correct location is used in all cases. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 3af24adf996e110dc4ac8d6b393e9318ca586bcc https://github.com/oracle/dtrace-utils/commit/3af24adf996e110dc4ac8d6b393e9318ca586bcc Author: Eugene Loh Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M test/unittest/usdt/tst.pidprobes.sh Log Message: ----------- test: Adapt USDT PC search for USDT LTO changes To check USDT PCs, we looked at disassembly for characteristics that indicated USDT probes. With LTO, however, USDT instrumentation has changed. Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. Note that tst.pidargs.sh and tst.pidargmap.sh depend on tst.pidprobes.sh. Therefore, those tests also benefit from this change. They do not yet pass, however, since index 0 for args[] is said to be out of range. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/4258ce213541...3af24adf996e To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From sam at gentoo.org Sun Jun 8 01:42:04 2025 From: sam at gentoo.org (Sam James) Date: Sun, 08 Jun 2025 02:42:04 +0100 Subject: [DTrace-devel] [PATCH v2 0/4] ELF note-based USDT support In-Reply-To: <407bef64-903d-43a0-a5e9-071eef13c27d@oracle.com> References: <20250129145522.512341-1-alan.maguire@oracle.com> <407bef64-903d-43a0-a5e9-071eef13c27d@oracle.com> Message-ID: <87ikl7uhzn.fsf@gentoo.org> Alan Maguire via DTrace-devel writes: > 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. Any update on this? I'd really love to start wiring up support for these in packages. I guess it interacts heavily with the work Kris has been doing on making LTO work with USDT though? cheeers, sam > > Alan > > [...] From kris.van.hees at oracle.com Sun Jun 8 03:08:29 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Sat, 7 Jun 2025 23:08:29 -0400 Subject: [DTrace-devel] [PATCH v2 0/4] ELF note-based USDT support In-Reply-To: <87ikl7uhzn.fsf@gentoo.org> References: <20250129145522.512341-1-alan.maguire@oracle.com> <407bef64-903d-43a0-a5e9-071eef13c27d@oracle.com> <87ikl7uhzn.fsf@gentoo.org> Message-ID: On Sun, Jun 08, 2025 at 02:42:04AM +0100, Sam James wrote: > Alan Maguire via DTrace-devel writes: > > > 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. > > Any update on this? I'd really love to start wiring up support for these > in packages. I guess it interacts heavily with the work Kris has been > doing on making LTO work with USDT though? Yes, the USDT rework I actually just completed is a pre-condition of getting support for stapsdt probes in DTrace. With the new USDT approach in place, this series can be revisited and adjusted to make use of what I introduced. Kris From noreply at github.com Sun Jun 8 04:20:15 2025 From: noreply at github.com (euloh) Date: Sat, 07 Jun 2025 21:20:15 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] aa6366: test: allow overriding CC, OBJCOPY, OBJDUMP, NM, ... Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: aa63660a7cfcdeb1daf4fb63f1c15f75a1693064 https://github.com/oracle/dtrace-utils/commit/aa63660a7cfcdeb1daf4fb63f1c15f75a1693064 Author: Eugene Loh Date: 2025-06-03 (Tue, 03 Jun 2025) Changed paths: M runtest.sh M test/expensive/locking/tst.DestructionDoubleUnlock.sh M test/internals/headers/tst.header-endianness.sh M test/stress/options/tst.cpu-syscall.sh M test/unittest/aggs/tst.aggmod_full2.sh M test/unittest/arrays/tst.uregsarray-check.sh M test/unittest/bitfields/tst.bitfield-offset.x M test/unittest/builtinvar/tst.errno3.sh M test/unittest/builtinvar/tst.tid_pid.sh M test/unittest/dtrace-util/tst.ListProbesArgsUSDT.sh M test/unittest/dtrace-util/tst.ListProbesFuncUSDT.sh M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh M test/unittest/dtrace-util/tst.ListProbesNameUSDT.sh M test/unittest/dtrace-util/tst.ListProbesProviderUSDT.sh M test/unittest/fbtprovider/tst.entryargs2.sh M test/unittest/funcs/copyout/tst.copyout.sh M test/unittest/funcs/copyoutstr/tst.copyoutstr.sh M test/unittest/misc/tst.include.sh M test/unittest/options/tst.cpu-syscall.sh M test/unittest/options/tst.ctypes.sh M test/unittest/options/tst.dtypes.sh M test/unittest/options/tst.linktype.sh M test/unittest/options/tst.strip.sh M test/unittest/pid/tst.dash.sh M test/unittest/pid/tst.offsets.sh M test/unittest/pid/tst.provregex1.sh M test/unittest/pid/tst.provregex2.sh M test/unittest/pid/tst.provregex3.sh M test/unittest/pid/tst.provregex4.sh M test/unittest/usdt/tst.allargs.sh M test/unittest/usdt/tst.badguess.sh M test/unittest/usdt/tst.badguess.x M test/unittest/usdt/tst.dlclose1.sh M test/unittest/usdt/tst.dlclose2.sh M test/unittest/usdt/tst.dlclose3.sh M test/unittest/usdt/tst.dlclose4.sh M test/unittest/usdt/tst.eliminate.sh M test/unittest/usdt/tst.enable_pid.sh M test/unittest/usdt/tst.enabled.sh M test/unittest/usdt/tst.enabled2.sh M test/unittest/usdt/tst.entryreturn.sh M test/unittest/usdt/tst.exec-dof-replacement.sh M test/unittest/usdt/tst.execstack.sh M test/unittest/usdt/tst.fork.sh M test/unittest/usdt/tst.guess32.sh M test/unittest/usdt/tst.guess64.sh M test/unittest/usdt/tst.header.sh M test/unittest/usdt/tst.lingering.sh M test/unittest/usdt/tst.link-idempotence.sh M test/unittest/usdt/tst.linkpriv.sh M test/unittest/usdt/tst.linkunpriv.sh M test/unittest/usdt/tst.manyprobes.sh M test/unittest/usdt/tst.manyprocs.sh M test/unittest/usdt/tst.multiple.sh M test/unittest/usdt/tst.multiprov-dupprobe-shlibs.sh M test/unittest/usdt/tst.multitrace.sh M test/unittest/usdt/tst.nusdtprobes.sh M test/unittest/usdt/tst.onlyenabled.sh M test/unittest/usdt/tst.pidprobes.sh M test/unittest/usdt/tst.pie.sh M test/unittest/usdt/tst.reeval.sh M test/unittest/usdt/tst.static.sh M test/unittest/usdt/tst.static2.sh M test/unittest/usdt/tst.user.sh M test/utils/workload_analyze_loop.sh Log Message: ----------- test: allow overriding CC, OBJCOPY, OBJDUMP, NM, ... Bug: https://github.com/oracle/dtrace-utils/issues/75 Signed-off-by: Sam James Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Commit: cf3da5d629c5ec7431ebbde1d589ee77aa404b57 https://github.com/oracle/dtrace-utils/commit/cf3da5d629c5ec7431ebbde1d589ee77aa404b57 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libdtrace/dt_provider.c M libdtrace/dt_provider.h Log Message: ----------- provider: fix registering fbt and rawfbt twice Now that rawfbt has been integrated into the fbt provider, it no longer needs to be in the list of providers to call populate() in. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 671679ca7109b03fb9fd0d75cad29d50d9ca6a9b https://github.com/oracle/dtrace-utils/commit/671679ca7109b03fb9fd0d75cad29d50d9ca6a9b Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libdtrace/dt_provider.c Log Message: ----------- providers: loop through all providers for discovery The discovery of probes was tied to the static list of providers that are called on init. It should iterate over all providers that are in fact registered, i.e. the dt_provs hash. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: a717b347fd93f5463ff72d6b7a968d013d00a4cf https://github.com/oracle/dtrace-utils/commit/a717b347fd93f5463ff72d6b7a968d013d00a4cf Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libdtrace/dt_open.c M libdtrace/dt_version.h Log Message: ----------- Only include dt_git_version.h where needed Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 8f650c85424719ec60f5866361958f289f5f5cab https://github.com/oracle/dtrace-utils/commit/8f650c85424719ec60f5866361958f289f5f5cab Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libcommon/dof_parser.c Log Message: ----------- dof_parser: remove pointless comment Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 54213ccfaff8e209d8b61ca9d4ffd40d693942c7 https://github.com/oracle/dtrace-utils/commit/54213ccfaff8e209d8b61ca9d4ffd40d693942c7 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dtprobed.c M libcommon/dof_parser.c M libcommon/dof_parser.h Log Message: ----------- dof_parser: restructure the dof_copyin*() code All logic for reading data from the DOF parser pipe is now consolidated in dof_copyin(). Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: 65d56b1c713ad22857056604c7ec9dfc792ca3f5 https://github.com/oracle/dtrace-utils/commit/65d56b1c713ad22857056604c7ec9dfc792ca3f5 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dof_stash.c M dtprobed/dof_stash.h M dtprobed/dtprobed.c M libcommon/Build R libcommon/dof_parser.c R libcommon/dof_parser.h R libcommon/dof_parser_host.c A libcommon/usdt_parser.c A libcommon/usdt_parser.h A libcommon/usdt_parser_dof.c A libcommon/usdt_parser_host.c M libdtrace/dt_pid.c Log Message: ----------- dof_parser: generic parser framework to support multiple parsers To prepare for non-DOF section based USDT probe definitions, the data passed from dtprobed to the USDT data parser is more generic. The dof_helper_t structure is passed first, followed by a block count, and that number of data blocks, passed as a size followed by the content. Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: b90f5b95fed57cb0f49aed7eef26cad8e0c09d6d https://github.com/oracle/dtrace-utils/commit/b90f5b95fed57cb0f49aed7eef26cad8e0c09d6d Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dtprobed.c Log Message: ----------- dtprobed: fix probe name debug output Debug output while reading dof_parsed_t structures was printing the probe names as provider->provider.name and probe->probe.name, but probe.name is a 0-separated concatenation of the probe name elements. It only printed the module name. Corrected to print the full probe name. Also moved it to the proper place (when a new probe is read rather than for every tracepoint). Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Reviewed-by: Eugene Loh Commit: 3350ae4fc291cc2f8d021158805769e952ddebed https://github.com/oracle/dtrace-utils/commit/3350ae4fc291cc2f8d021158805769e952ddebed Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libcommon/Build A libcommon/dt_htab.c A libcommon/dt_htab.h M libdtrace/Build M libdtrace/dt_consume.c R libdtrace/dt_htab.c R libdtrace/dt_htab.h M libdtrace/dt_kernel_module.c M libdtrace/dt_module.c M libdtrace/dt_open.c M libdtrace/dt_probe.c M libdtrace/dt_provider.c M libdtrace/dt_symtab.c Log Message: ----------- htab: move htab handling to libcommon Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 3530b90b3486e5de33773390f8cf1bf9546fe9c3 https://github.com/oracle/dtrace-utils/commit/3530b90b3486e5de33773390f8cf1bf9546fe9c3 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libcommon/dt_htab.c M libcommon/dt_htab.h M libdtrace/dt_string.c M libdtrace/dt_string.h Log Message: ----------- htab: move str2hval() to dt_htab Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 2cbb15865c8f07dce97e3a673886c812cd62e6c4 https://github.com/oracle/dtrace-utils/commit/2cbb15865c8f07dce97e3a673886c812cd62e6c4 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dtprobed.c Log Message: ----------- dtprobed: make sure that retry one time means exactly that Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 22b24012109bf79522bc0f2e2d2a9c5b0136135f https://github.com/oracle/dtrace-utils/commit/22b24012109bf79522bc0f2e2d2a9c5b0136135f Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M include/dtrace/ioctl.h Log Message: ----------- usdt: add HASUSDT to the helper ioctl interface Signed-off-by: Kris Van Hees Reviewed-by: Eugene Loh Commit: b7d53876071e1a600c3b2725f486e64fd72d2507 https://github.com/oracle/dtrace-utils/commit/b7d53876071e1a600c3b2725f486e64fd72d2507 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M dtprobed/dof_stash.c M dtprobed/dof_stash.h M dtprobed/dtprobed.c M libcommon/Build M libcommon/usdt_parser.c M libcommon/usdt_parser.h M libcommon/usdt_parser_dof.c M libcommon/usdt_parser_host.c A libcommon/usdt_parser_notes.c A uts/common/sys/usdt_note_defs.h Log Message: ----------- dtprobed, usdt parser: add support for ELF notes-based USDT Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: ee8f0d96e441a417a40254d50fec4ba92f7cdfbd https://github.com/oracle/dtrace-utils/commit/ee8f0d96e441a417a40254d50fec4ba92f7cdfbd Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M include/dtrace/pid.h M libdtrace/dt_cg.c M libdtrace/dt_cg.h M libdtrace/dt_pid.c M libdtrace/dt_prov_uprobe.c Log Message: ----------- usdt: implement tracing USDT probes specified in ELF notes Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 11d545fa81f9047c730e61f79bf695eaa163f8cf https://github.com/oracle/dtrace-utils/commit/11d545fa81f9047c730e61f79bf695eaa163f8cf Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M libdtrace/drti.c M libdtrace/dt_dof.c M libdtrace/dt_impl.h M libdtrace/dt_link.c M libdtrace/dt_program.c M test/triggers/Build A test/triggers/usdt-tst-arg-const-prov.d A test/triggers/usdt-tst-arg-const.c A test/triggers/usdt-tst-arg-reg-prov.d A test/triggers/usdt-tst-arg-reg.c A test/triggers/usdt-tst-deref-decode-prov.d A test/triggers/usdt-tst-deref-decode.aarch64.c A test/triggers/usdt-tst-deref-decode.x86_64.c M test/unittest/options/tst.strip.sh A test/unittest/usdt/err.wrong-probe-argc-cc.sh A test/unittest/usdt/err.wrong-probe-argc-rt.sh A test/unittest/usdt/err.wrong-probe.sh A test/unittest/usdt/err.wrong-prov.sh A test/unittest/usdt/tst.arg-reg.d A test/unittest/usdt/tst.arg-reg.r R test/unittest/usdt/tst.badguess.sh R test/unittest/usdt/tst.badguess.x A test/unittest/usdt/tst.const.d A test/unittest/usdt/tst.const.r A test/unittest/usdt/tst.deref-decode.d R test/unittest/usdt/tst.guess32.sh R test/unittest/usdt/tst.guess32.x M test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p M test/utils/Build M test/utils/showUSDT.c M uts/common/sys/sdt.h A uts/common/sys/usdt.h A uts/common/sys/usdt_gennote.h A uts/common/sys/usdt_internal.h Log Message: ----------- link: implement USDT probe definitions in ELF notes Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 455d7d4589472a9a135350841b1a036eeeda8db8 https://github.com/oracle/dtrace-utils/commit/455d7d4589472a9a135350841b1a036eeeda8db8 Author: Kris Van Hees Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh Log Message: ----------- test: fix test for non-installed testing On a system without DTrace installed, cannot be found, causing this test to fail. Use test_cppflags to ensure the correct location is used in all cases. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 3af24adf996e110dc4ac8d6b393e9318ca586bcc https://github.com/oracle/dtrace-utils/commit/3af24adf996e110dc4ac8d6b393e9318ca586bcc Author: Eugene Loh Date: 2025-06-07 (Sat, 07 Jun 2025) Changed paths: M test/unittest/usdt/tst.pidprobes.sh Log Message: ----------- test: Adapt USDT PC search for USDT LTO changes To check USDT PCs, we looked at disassembly for characteristics that indicated USDT probes. With LTO, however, USDT instrumentation has changed. Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. Note that tst.pidargs.sh and tst.pidargmap.sh depend on tst.pidprobes.sh. Therefore, those tests also benefit from this change. They do not yet pass, however, since index 0 for args[] is said to be out of range. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/38c9ea5126d8...3af24adf996e To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From noreply at github.com Sun Jun 8 04:48:11 2025 From: noreply at github.com (euloh) Date: Sat, 07 Jun 2025 21:48:11 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] e8e924: link: implement USDT probe definitions in ELF notes Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: e8e924424b489ac0e12c59cf2c1e0a189527c123 https://github.com/oracle/dtrace-utils/commit/e8e924424b489ac0e12c59cf2c1e0a189527c123 Author: Kris Van Hees Date: 2025-06-08 (Sun, 08 Jun 2025) Changed paths: M libdtrace/drti.c M libdtrace/dt_dof.c M libdtrace/dt_impl.h M libdtrace/dt_link.c M libdtrace/dt_program.c M test/triggers/Build A test/triggers/usdt-tst-arg-const-prov.d A test/triggers/usdt-tst-arg-const.c A test/triggers/usdt-tst-arg-reg-prov.d A test/triggers/usdt-tst-arg-reg.c A test/triggers/usdt-tst-deref-decode-prov.d A test/triggers/usdt-tst-deref-decode.aarch64.c A test/triggers/usdt-tst-deref-decode.x86_64.c M test/unittest/options/tst.linktype.r M test/unittest/options/tst.strip.sh A test/unittest/usdt/err.wrong-probe-argc-cc.sh A test/unittest/usdt/err.wrong-probe-argc-rt.sh A test/unittest/usdt/err.wrong-probe.sh A test/unittest/usdt/err.wrong-prov.sh A test/unittest/usdt/tst.arg-reg.d A test/unittest/usdt/tst.arg-reg.r R test/unittest/usdt/tst.badguess.sh R test/unittest/usdt/tst.badguess.x A test/unittest/usdt/tst.const.d A test/unittest/usdt/tst.const.r A test/unittest/usdt/tst.deref-decode.d R test/unittest/usdt/tst.guess32.sh R test/unittest/usdt/tst.guess32.x M test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p M test/utils/Build M test/utils/showUSDT.c M uts/common/sys/sdt.h A uts/common/sys/usdt.h A uts/common/sys/usdt_gennote.h A uts/common/sys/usdt_internal.h Log Message: ----------- link: implement USDT probe definitions in ELF notes Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 741c7403eb61cf8586fba9c2672f03288ba142cd https://github.com/oracle/dtrace-utils/commit/741c7403eb61cf8586fba9c2672f03288ba142cd Author: Kris Van Hees Date: 2025-06-08 (Sun, 08 Jun 2025) Changed paths: M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh Log Message: ----------- test: fix test for non-installed testing On a system without DTrace installed, cannot be found, causing this test to fail. Use test_cppflags to ensure the correct location is used in all cases. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 0d21c8484b649b028a7b54fc1221be7e7e3bb9aa https://github.com/oracle/dtrace-utils/commit/0d21c8484b649b028a7b54fc1221be7e7e3bb9aa Author: Eugene Loh Date: 2025-06-08 (Sun, 08 Jun 2025) Changed paths: M test/unittest/usdt/tst.pidprobes.sh Log Message: ----------- test: Adapt USDT PC search for USDT LTO changes To check USDT PCs, we looked at disassembly for characteristics that indicated USDT probes. With LTO, however, USDT instrumentation has changed. Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. Note that tst.pidargs.sh and tst.pidargmap.sh depend on tst.pidprobes.sh. Therefore, those tests also benefit from this change. They do not yet pass, however, since index 0 for args[] is said to be out of range. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/3af24adf996e...0d21c8484b64 To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From eugene.loh at oracle.com Sun Jun 8 05:36:20 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Sun, 8 Jun 2025 01:36:20 -0400 Subject: [DTrace-devel] [PATCH] test: Wait for output to flush out in enable_pid Message-ID: <20250608053620.15468-1-eugene.loh@oracle.com> From: Eugene Loh Our luck with this test has been quite good, but it sometimes fails to show its last lines of output. That is, we send a USR1 to the trigger processes to set off the final output and we immediately cat the output files. If there is any delay, the last output will be missing. Add a short delay so that the last output will be seen. Signed-off-by: Eugene Loh --- test/unittest/usdt/tst.enable_pid.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/unittest/usdt/tst.enable_pid.sh b/test/unittest/usdt/tst.enable_pid.sh index 7f4f68698..5a151c767 100755 --- a/test/unittest/usdt/tst.enable_pid.sh +++ b/test/unittest/usdt/tst.enable_pid.sh @@ -172,6 +172,9 @@ for pid in 1 $pid1 $pid2 '*'; do kill -USR1 $pid2 done +# wait for last of the output to flush out +sleep 2 + echo done echo "========== out 1"; cat out.1 echo "========== out 2"; cat out.2 -- 2.43.5 From noreply at github.com Mon Jun 9 16:30:47 2025 From: noreply at github.com (euloh) Date: Mon, 09 Jun 2025 09:30:47 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] 458b67: link: implement USDT probe definitions in ELF notes Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: 458b6792c7468ff6943abb67f192f60b3b6e9f1c https://github.com/oracle/dtrace-utils/commit/458b6792c7468ff6943abb67f192f60b3b6e9f1c Author: Kris Van Hees Date: 2025-06-08 (Sun, 08 Jun 2025) Changed paths: M libdtrace/drti.c M libdtrace/dt_dof.c M libdtrace/dt_impl.h M libdtrace/dt_link.c M libdtrace/dt_program.c M test/triggers/Build A test/triggers/usdt-tst-arg-const-prov.d A test/triggers/usdt-tst-arg-const.c A test/triggers/usdt-tst-arg-reg-prov.d A test/triggers/usdt-tst-arg-reg.c A test/triggers/usdt-tst-deref-decode-prov.d A test/triggers/usdt-tst-deref-decode.aarch64.c A test/triggers/usdt-tst-deref-decode.x86_64.c M test/unittest/options/tst.linktype.r M test/unittest/options/tst.strip.sh A test/unittest/usdt/err.wrong-probe-argc-cc.sh A test/unittest/usdt/err.wrong-probe-argc-rt.sh A test/unittest/usdt/err.wrong-probe.sh A test/unittest/usdt/err.wrong-prov.sh A test/unittest/usdt/tst.arg-reg.d A test/unittest/usdt/tst.arg-reg.r R test/unittest/usdt/tst.badguess.sh R test/unittest/usdt/tst.badguess.x A test/unittest/usdt/tst.const.d A test/unittest/usdt/tst.const.r A test/unittest/usdt/tst.deref-decode.d R test/unittest/usdt/tst.guess32.sh R test/unittest/usdt/tst.guess32.x M test/unittest/usdt/tst.multiprov-dupprobe-shlibs.r.p M test/utils/Build M test/utils/showUSDT.c M uts/Build M uts/common/sys/sdt.h A uts/common/sys/usdt.h A uts/common/sys/usdt_gennote.h A uts/common/sys/usdt_internal.h Log Message: ----------- link: implement USDT probe definitions in ELF notes Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 6d88f1a212af94693cb6b3d9525985d379eb01fa https://github.com/oracle/dtrace-utils/commit/6d88f1a212af94693cb6b3d9525985d379eb01fa Author: Kris Van Hees Date: 2025-06-08 (Sun, 08 Jun 2025) Changed paths: M test/unittest/dtrace-util/tst.ListProbesModuleUSDT.sh Log Message: ----------- test: fix test for non-installed testing On a system without DTrace installed, cannot be found, causing this test to fail. Use test_cppflags to ensure the correct location is used in all cases. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 30c8be7604c839fa27d630a7b795c4349d462148 https://github.com/oracle/dtrace-utils/commit/30c8be7604c839fa27d630a7b795c4349d462148 Author: Eugene Loh Date: 2025-06-08 (Sun, 08 Jun 2025) Changed paths: M test/unittest/usdt/tst.pidprobes.sh Log Message: ----------- test: Adapt USDT PC search for USDT LTO changes To check USDT PCs, we looked at disassembly for characteristics that indicated USDT probes. With LTO, however, USDT instrumentation has changed. Therefore, use showUSDT in tst.pidprobes.sh to extract USDT PCs. Note that tst.pidargs.sh and tst.pidargmap.sh depend on tst.pidprobes.sh. Therefore, those tests also benefit from this change. They do not yet pass, however, since index 0 for args[] is said to be out of range. Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees Compare: https://github.com/oracle/dtrace-utils/compare/0d21c8484b64...30c8be7604c8 To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From eugene.loh at oracle.com Mon Jun 9 18:06:47 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Mon, 9 Jun 2025 14:06:47 -0400 Subject: [DTrace-devel] [PATCH] test: Suppress some white space Message-ID: <20250609180647.4424-1-eugene.loh@oracle.com> From: Eugene Loh The test suite turns pointers into "{ptr}" so that results comparisons will not be sensitive to particular pointer offset values. If these offsets change in width -- say, from 0xf0 to 0x100 -- the amount of white space in the postprocessed output can change. Add additional postprocessing to a test that sometimes fails due to this problem. Signed-off-by: Eugene Loh --- test/unittest/aggs/tst.ustack.r | 32 +++++++++++++++---------------- test/unittest/aggs/tst.ustack.r.p | 3 +++ 2 files changed, 19 insertions(+), 16 deletions(-) create mode 100755 test/unittest/aggs/tst.ustack.r.p diff --git a/test/unittest/aggs/tst.ustack.r b/test/unittest/aggs/tst.ustack.r index ed26cc5f3..271a0b30c 100644 --- a/test/unittest/aggs/tst.ustack.r +++ b/test/unittest/aggs/tst.ustack.r @@ -1,18 +1,18 @@ - ustack-tst-basic`myfunc_y+{ptr} - ustack-tst-basic`myfunc_y - ustack-tst-basic - ustack-tst-basic`myfunc_y + ustack-tst-basic`myfunc_y+{ptr} + ustack-tst-basic`myfunc_y + ustack-tst-basic + ustack-tst-basic`myfunc_y - ustack-tst-basic`myfunc_z+{ptr} - ustack-tst-basic`myfunc_y+{ptr} - ustack-tst-basic`myfunc_x+{ptr} - ustack-tst-basic`myfunc_w+{ptr} - ustack-tst-basic`myfunc_v+{ptr} + ustack-tst-basic`myfunc_z+{ptr} + ustack-tst-basic`myfunc_y+{ptr} + ustack-tst-basic`myfunc_x+{ptr} + ustack-tst-basic`myfunc_w+{ptr} + ustack-tst-basic`myfunc_v+{ptr} - 97 ustack-tst-basic`myfunc_y+{ptr} ustack-tst-basic`myfunc_y ustack-tst-basic ustack-tst-basic`myfunc_y - ustack-tst-basic`myfunc_z+{ptr} - ustack-tst-basic`myfunc_y+{ptr} - ustack-tst-basic`myfunc_x+{ptr} - ustack-tst-basic`myfunc_w+{ptr} - ustack-tst-basic`myfunc_v+{ptr} - 4 1234 + 97 ustack-tst-basic`myfunc_y+{ptr} ustack-tst-basic`myfunc_y ustack-tst-basic ustack-tst-basic`myfunc_y + ustack-tst-basic`myfunc_z+{ptr} + ustack-tst-basic`myfunc_y+{ptr} + ustack-tst-basic`myfunc_x+{ptr} + ustack-tst-basic`myfunc_w+{ptr} + ustack-tst-basic`myfunc_v+{ptr} + 4 1234 diff --git a/test/unittest/aggs/tst.ustack.r.p b/test/unittest/aggs/tst.ustack.r.p new file mode 100755 index 000000000..16a0451c4 --- /dev/null +++ b/test/unittest/aggs/tst.ustack.r.p @@ -0,0 +1,3 @@ +#!/usr/bin/gawk -f + +{ gsub(/ +/, " "); print; } -- 2.43.5 From noreply at github.com Tue Jun 10 05:25:12 2025 From: noreply at github.com (Kris Van Hees) Date: Mon, 09 Jun 2025 22:25:12 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] 6b7ccc: Update NEWS and dtrace.spec for release 2.0.3 Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: 6b7ccc9d662f4bbdfe095196471c54c6dc0d1cba https://github.com/oracle/dtrace-utils/commit/6b7ccc9d662f4bbdfe095196471c54c6dc0d1cba Author: Kris Van Hees Date: 2025-06-10 (Tue, 10 Jun 2025) Changed paths: M NEWS M dtrace.spec Log Message: ----------- Update NEWS and dtrace.spec for release 2.0.3 Signed-off-by: Kris Van Hees To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From alan.maguire at oracle.com Tue Jun 10 13:58:09 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Tue, 10 Jun 2025 14:58:09 +0100 Subject: [DTrace-devel] [PATCH v2 0/4] DTrace TCP provider Message-ID: <20250610135813.15746-1-alan.maguire@oracle.com> This series is a first draft of TCP provider support, where the probes are implemented via underlying fbt and sdt probes. Due to the use of the sock/inet_sock_set_state tracepoint, intended for ~5.15 kernels and later. Tried replacing this with fbt::tcp_set_state:entry but this misses a few state transitions, so stuck with using the tracepoint. All tests under test/unittest/tcp pass unmodified on an upstream (6.15) kernel and 5.15 UEK7U3 kernel. It implements all documented TCP provider probes: accept-established, accept-refused, connnect-request, connect-established, connect-refused, receive, send, state-change Changes since RFC: - fixed issues with test failures on UEK7 due to missing SYN_RCV state change - moved get_member() to dt_cg.c (patch 1) Alan Maguire (4): dtrace: move get_member() to dt_cg.c dt_impl: bump number of TSLOTS to 8 dtrace: add tcp provider dtrace: sync dlibs with tcp.d, ip.d and net.d changes dlibs/aarch64/5.14/ip.d | 1 - dlibs/aarch64/5.14/net.d | 6 +- dlibs/aarch64/5.14/tcp.d | 52 ++--- dlibs/aarch64/5.16/ip.d | 1 - dlibs/aarch64/5.16/net.d | 6 +- dlibs/aarch64/5.16/tcp.d | 52 ++--- dlibs/aarch64/6.1/ip.d | 1 - dlibs/aarch64/6.1/net.d | 6 +- dlibs/aarch64/6.1/tcp.d | 52 ++--- dlibs/aarch64/6.10/ip.d | 1 - dlibs/aarch64/6.10/net.d | 6 +- dlibs/aarch64/6.10/tcp.d | 52 ++--- dlibs/x86_64/5.14/ip.d | 1 - dlibs/x86_64/5.14/net.d | 6 +- dlibs/x86_64/5.14/tcp.d | 52 ++--- dlibs/x86_64/5.16/ip.d | 1 - dlibs/x86_64/5.16/net.d | 6 +- dlibs/x86_64/5.16/tcp.d | 52 ++--- dlibs/x86_64/6.1/ip.d | 1 - dlibs/x86_64/6.1/net.d | 6 +- dlibs/x86_64/6.1/tcp.d | 52 ++--- dlibs/x86_64/6.10/ip.d | 1 - dlibs/x86_64/6.10/net.d | 6 +- dlibs/x86_64/6.10/tcp.d | 52 ++--- libdtrace/Build | 2 + libdtrace/dt_cg.c | 39 ++++ libdtrace/dt_cg.h | 2 + libdtrace/dt_impl.h | 2 +- libdtrace/dt_prov_ip.c | 45 +---- libdtrace/dt_prov_tcp.c | 405 +++++++++++++++++++++++++++++++++++++++ libdtrace/dt_provider.c | 1 + libdtrace/dt_provider.h | 1 + libdtrace/ip.d | 1 - libdtrace/net.d | 6 +- libdtrace/tcp.d | 52 ++--- 35 files changed, 761 insertions(+), 267 deletions(-) create mode 100644 libdtrace/dt_prov_tcp.c -- 2.39.3 From alan.maguire at oracle.com Tue Jun 10 13:58:10 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Tue, 10 Jun 2025 14:58:10 +0100 Subject: [DTrace-devel] [PATCH v2 1/4] dtrace: move get_member() to dt_cg.c In-Reply-To: <20250610135813.15746-1-alan.maguire@oracle.com> References: <20250610135813.15746-1-alan.maguire@oracle.com> Message-ID: <20250610135813.15746-2-alan.maguire@oracle.com> It will be used by both dt_prov_ip.c and dt_prov_tcp.c. Signed-off-by: Alan Maguire --- libdtrace/dt_cg.c | 39 ++++++++++++++++++++++++++++++++++++ libdtrace/dt_cg.h | 2 ++ libdtrace/dt_prov_ip.c | 45 ++++-------------------------------------- 3 files changed, 45 insertions(+), 41 deletions(-) diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c index c68a5d45..ad761d3b 100644 --- a/libdtrace/dt_cg.c +++ b/libdtrace/dt_cg.c @@ -1901,6 +1901,45 @@ dt_cg_ctf_offsetof(const char *structname, const char *membername, return (ctm.ctm_offset / NBBY); } +/* + * Retrieve the value of a member in a given struct. + * + * Entry: + * reg = TYPE *ptr + * + * Return: + * %r0 = ptr->member + * Clobbers: + * %r1 .. %r5 + */ +int +dt_cg_get_member(dt_pcb_t *pcb, const char *name, int reg, + const char *member) +{ + dtrace_hdl_t *dtp = pcb->pcb_hdl; + dt_irlist_t *dlp = &pcb->pcb_ir; + dtrace_typeinfo_t tt; + ctf_membinfo_t ctm; + size_t size; + uint_t ldop; + + if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_KMODS, name, &tt) == -1 || + ctf_member_info(tt.dtt_ctfp, tt.dtt_type, member, &ctm) == CTF_ERR) + return -1; + + ldop = dt_cg_ldsize(NULL, tt.dtt_ctfp, ctm.ctm_type, &size); + + emit(dlp, BPF_MOV_REG(BPF_REG_3, reg)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, ctm.ctm_offset / NBBY)); + emit(dlp, BPF_MOV_IMM(BPF_REG_2, size)); + emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); + emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_BASE)); + emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_kernel])); + emit(dlp, BPF_LOAD(ldop, BPF_REG_0, BPF_REG_FP, DT_TRAMP_SP_BASE)); + + return 0; +} + static void dt_cg_act_breakpoint(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind) { diff --git a/libdtrace/dt_cg.h b/libdtrace/dt_cg.h index fb26c125..c4aa610a 100644 --- a/libdtrace/dt_cg.h +++ b/libdtrace/dt_cg.h @@ -43,6 +43,8 @@ extern void dt_cg_tramp_epilogue_advance(dt_pcb_t *pcb, dt_activity_t act); extern void dt_cg_tramp_error(dt_pcb_t *pcb); extern int dt_cg_ctf_offsetof(const char *structname, const char *membername, size_t *sizep, int relaxed); +extern int dt_cg_get_member(dt_pcb_t *pcb, const char *name, int reg, + const char *member); extern uint_t dt_cg_ldsize(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type, ssize_t *ret_size); extern uint_t bpf_ldst_size(ssize_t size, int store); diff --git a/libdtrace/dt_prov_ip.c b/libdtrace/dt_prov_ip.c index c4a3a6e2..37f91e3d 100644 --- a/libdtrace/dt_prov_ip.c +++ b/libdtrace/dt_prov_ip.c @@ -62,43 +62,6 @@ static int populate(dtrace_hdl_t *dtp) probe_args, probes); } -/* - * Retrieve the value of a member in a given struct. - * - * Entry: - * reg = TYPE *ptr - * - * Return: - * %r0 = ptr->member - * Clobbers: - * %r1 .. %r5 - */ -static int get_member(dt_pcb_t *pcb, const char *name, int reg, - const char *member) { - dtrace_hdl_t *dtp = pcb->pcb_hdl; - dt_irlist_t *dlp = &pcb->pcb_ir; - dtrace_typeinfo_t tt; - ctf_membinfo_t ctm; - size_t size; - uint_t ldop; - - if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_KMODS, name, &tt) == -1 || - ctf_member_info(tt.dtt_ctfp, tt.dtt_type, member, &ctm) == CTF_ERR) - return -1; - - ldop = dt_cg_ldsize(NULL, tt.dtt_ctfp, ctm.ctm_type, &size); - - emit(dlp, BPF_MOV_REG(BPF_REG_3, reg)); - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, ctm.ctm_offset / NBBY)); - emit(dlp, BPF_MOV_IMM(BPF_REG_2, size)); - emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_FP)); - emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, DT_TRAMP_SP_BASE)); - emit(dlp, BPF_CALL_HELPER(dtp->dt_bpfhelper[BPF_FUNC_probe_read_kernel])); - emit(dlp, BPF_LOAD(ldop, BPF_REG_0, BPF_REG_FP, DT_TRAMP_SP_BASE)); - - return 0; -} - /* * Generate a BPF trampoline for a SDT probe. * @@ -142,7 +105,7 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_6)); - get_member(pcb, "struct sk_buff", BPF_REG_6, "sk"); + dt_cg_get_member(pcb, "struct sk_buff", BPF_REG_6, "sk"); emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_0)); /* @@ -150,11 +113,11 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) * skb_network_header(skb) = (include/linux/ip.h) * skb->head + skb->network_header (include/linux/skbuff.h) */ - get_member(pcb, "struct sk_buff", BPF_REG_6, "head"); + dt_cg_get_member(pcb, "struct sk_buff", BPF_REG_6, "head"); emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(2), BPF_REG_0)); emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(4), BPF_REG_0)); emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(5), BPF_REG_0)); - get_member(pcb, "struct sk_buff", BPF_REG_6, "network_header"); + dt_cg_get_member(pcb, "struct sk_buff", BPF_REG_6, "network_header"); emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_7, DMST_ARG(2), BPF_REG_0)); emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_7, DMST_ARG(4), BPF_REG_0)); emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_7, DMST_ARG(5), BPF_REG_0)); @@ -168,7 +131,7 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) else emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(5), 0)); - get_member(pcb, "struct sk_buff", BPF_REG_6, "dev"); + dt_cg_get_member(pcb, "struct sk_buff", BPF_REG_6, "dev"); emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(3), BPF_REG_0)); return 0; -- 2.39.3 From alan.maguire at oracle.com Tue Jun 10 13:58:11 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Tue, 10 Jun 2025 14:58:11 +0100 Subject: [DTrace-devel] [PATCH v2 2/4] dt_impl: bump number of TSLOTS to 8 In-Reply-To: <20250610135813.15746-1-alan.maguire@oracle.com> References: <20250610135813.15746-1-alan.maguire@oracle.com> Message-ID: <20250610135813.15746-3-alan.maguire@oracle.com> Because of the complexity of the TCP translators, more tslots are needed. Signed-off-by: Alan Maguire --- libdtrace/dt_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h index 68fb8ec5..10424f9c 100644 --- a/libdtrace/dt_impl.h +++ b/libdtrace/dt_impl.h @@ -218,7 +218,7 @@ typedef struct dt_kern_path { * - cleanpath() holds a prepended '/' char, a string, an appended '/' char, * and a terminating NUL char, or STRSZ + 3 chars altogether */ -#define DT_TSTRING_SLOTS 4 +#define DT_TSTRING_SLOTS 8 #define DT_TSTRING_SIZE(dtp) \ MAX(P2ROUNDUP((dtp)->dt_options[DTRACEOPT_STRSIZE] + 3, 8), \ 72) -- 2.39.3 From alan.maguire at oracle.com Tue Jun 10 13:58:12 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Tue, 10 Jun 2025 14:58:12 +0100 Subject: [DTrace-devel] [PATCH v2 3/4] dtrace: add tcp provider In-Reply-To: <20250610135813.15746-1-alan.maguire@oracle.com> References: <20250610135813.15746-1-alan.maguire@oracle.com> Message-ID: <20250610135813.15746-4-alan.maguire@oracle.com> Based upon various fbt probe points support TCP send, receive, state-change, accept-established, accept-refused, connect-request, connect-established and connect-refused probes. A few tweaks were needed to tcp.d to support the probes fully. Signed-off-by: Alan Maguire --- libdtrace/Build | 2 + libdtrace/dt_prov_tcp.c | 405 ++++++++++++++++++++++++++++++++++++++++ libdtrace/dt_provider.c | 1 + libdtrace/dt_provider.h | 1 + libdtrace/ip.d | 1 - libdtrace/net.d | 6 +- libdtrace/tcp.d | 52 +++--- 7 files changed, 443 insertions(+), 25 deletions(-) create mode 100644 libdtrace/dt_prov_tcp.c diff --git a/libdtrace/Build b/libdtrace/Build index 7e6e8a38..a5439354 100644 --- a/libdtrace/Build +++ b/libdtrace/Build @@ -59,6 +59,7 @@ libdtrace-build_SOURCES = dt_aggregate.c \ dt_prov_sched.c \ dt_prov_sdt.c \ dt_prov_syscall.c \ + dt_prov_tcp.c \ dt_prov_uprobe.c \ dt_provider.c \ dt_provider_sdt.c \ @@ -117,6 +118,7 @@ dt_prov_rawtp.c_CFLAGS := -Wno-pedantic dt_prov_sched.c_CFLAGS := -Wno-pedantic dt_prov_sdt.c_CFLAGS := -Wno-pedantic dt_prov_syscall.c_CFLAGS := -Wno-pedantic +dt_prov_tcp.c_CFLAGS := -Wno-pedantic dt_prov_uprobe.c_CFLAGS := -Wno-pedantic dt_debug.c_CFLAGS := -Wno-prio-ctor-dtor diff --git a/libdtrace/dt_prov_tcp.c b/libdtrace/dt_prov_tcp.c new file mode 100644 index 00000000..75e1e3a9 --- /dev/null +++ b/libdtrace/dt_prov_tcp.c @@ -0,0 +1,405 @@ +/* + * 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. + * + * The 'tcp' SDT provider for DTrace-specific probes. + */ +#include +#include +#include + +#include "dt_dctx.h" +#include "dt_cg.h" +#include "dt_provider_sdt.h" +#include "dt_probe.h" + +static const char prvname[] = "tcp"; +static const char modname[] = "vmlinux"; + +enum { + NET_PROBE_OUTBOUND = 0, + NET_PROBE_INBOUND, + NET_PROBE_STATE +}; + +static probe_dep_t probes[] = { + /* does not fire on UEK7 unless rawfbt; no idea why... */ + { "accept-established", + DTRACE_PROBESPEC_NAME, "rawfbt::tcp_init_transfer:entry" }, + { "accept-refused", + DTRACE_PROBESPEC_NAME, "fbt::tcp_v4_send_reset:entry" }, + { "accept-refused", + DTRACE_PROBESPEC_NAME, "fbt::tcp_v6_send_reset:entry" }, + { "connect-established", + DTRACE_PROBESPEC_NAME, "fbt::tcp_finish_connect:entry" }, + { "connect-refused", + DTRACE_PROBESPEC_NAME, "fbt::tcp_reset:entry" }, + { "connect-request", + DTRACE_PROBESPEC_NAME, "fbt::ip_queue_xmit:entry" }, + /* ip6_xmit has > 6 args so cannot fentry on aarch64; use rawfbt */ + { "connect-request", + DTRACE_PROBESPEC_NAME, "rawfbt::ip6_xmit:entry" }, + { "receive", + DTRACE_PROBESPEC_NAME, "fbt::tcp_rcv_established:entry" }, + { "receive", + DTRACE_PROBESPEC_NAME, "fbt::tcp_rcv_state_process:entry" }, + { "receive", + DTRACE_PROBESPEC_NAME, "fbt::tcp_v4_send_reset:entry" }, + { "send", + DTRACE_PROBESPEC_NAME, "fbt::ip_queue_xmit:entry" }, + /* ip_send_unicast_reply has 10 args so cannot fentry; use rawfbt */ + { "send", + DTRACE_PROBESPEC_NAME, "rawfbt::ip_send_unicast_reply:entry" }, + { "send", + DTRACE_PROBESPEC_NAME, "fbt::ip_build_and_send_pkt" }, + /* ip6_xmit has > 6 args so cannot fentry on aarch64; use rawfbt */ + { "send", + DTRACE_PROBESPEC_NAME, "rawfbt::ip6_xmit:entry" }, + { "state-change", + DTRACE_PROBESPEC_NAME, "sdt:::inet_sock_set_state" }, + { "state-change", + DTRACE_PROBESPEC_NAME, "fbt::tcp_time_wait:entry" }, + { "state-change", + DTRACE_PROBESPEC_NAME, "fbt::inet_csk_clone_lock:entry" }, + { NULL, } +}; + +static probe_arg_t probe_args[] = { + { "accept-established", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "accept-established", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "accept-established", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } }, + { "accept-established", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "accept-established", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "accept-established", 5, { 5, 0, "unsigned char", "int"} }, + { "accept-established", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "accept-established", 7, { 7, 0, "int", "int" } }, + + { "accept-refused", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "accept-refused", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "accept-refused", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } }, + { "accept-refused", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "accept-refused", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "accept-refused", 5, { 5, 0, "unsigned char", "int"} }, + { "accept-refused", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "accept-refused", 7, { 7, 0, "int", "int" } }, + + { "connect-established", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "connect-established", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "connect-established", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } }, + { "connect-established", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "connect-established", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "connect-established", 5, { 5, 0, "unsigned char", "int"} }, + { "connect-established", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "connect-established", 7, { 7, 0, "int", "int" } }, + + { "connect-refused", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "connect-refused", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "connect-refused", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } }, + { "connect-refused", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "connect-refused", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "connect-refused", 5, { 5, 0, "unsigned char", "int"} }, + { "connect-refused", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "connect-refused", 7, { 7, 0, "int", "int" } }, + + { "connect-request", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "connect-request", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "connect-request", 2, { 2, 0, "__dtrace_tcp_void_ip_t *", "ipinfo_t *" } }, + { "connect-request", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "connect-request", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "connect-request", 5, { 5, 0, "unsigned char", "int"} }, + { "connect-request", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "connect-request", 7, { 7, 0, "int", "int" } }, + + { "receive", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "receive", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "receive", 2, { 2, 0, "void_ip_t *", "ipinfo_t *" } }, + { "receive", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "receive", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "receive", 5, { 5, 0, "unsigned char", "int"} }, + { "receive", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "receive", 7, { 7, 0, "int", "int" } }, + + { "send", 0, { 0, 0, "struct sk_buff *", "pktinfo_t *" } }, + { "send", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "send", 2, { 2, 0, "__dtrace_tcp_void_ip_t *", "ipinfo_t *" } }, + { "send", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "send", 4, { 4, 0, "struct tcphdr *", "tcpinfo_t *" } }, + { "send", 5, { 5, 0, "unsigned char", "int"} }, + { "send", 6, { 6, 0, "unsigned char", "tcplsinfo_t *" } }, + { "send", 7, { 7, 0, "int", "int" } }, + + { "state-change", 0, { 0, 0, "void *", "void *", } }, + { "state-change", 1, { 1, 0, "struct sock *", "csinfo_t *" } }, + { "state-change", 2, { 2, 0, "void *", "void *" } }, + { "state-change", 3, { 3, 0, "struct tcp_sock *", "tcpsinfo_t *" } }, + { "state-change", 4, { 4, 0, "void *", "void *" } }, + { "state-change", 5, { 5, 0, "void *", "void *" } }, + { "state-change", 6, { 6, 0, "struct sock *", "tcplsinfo_t *" } }, + { "state-change", 7, { 7, 0, "int", "int" } }, + + { NULL, } +}; + +static const dtrace_pattr_t pattr = { +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, +}; + +/* + * Provide all the "tcp" SDT probes. + */ +static int populate(dtrace_hdl_t *dtp) +{ + return dt_sdt_populate(dtp, prvname, modname, &dt_tcp, &pattr, + probe_args, probes); +} + +/* + * Generate a BPF trampoline for a SDT probe. + * + * The trampoline function is called when a SDT probe triggers, and it must + * satisfy the following prototype: + * + * int dt_tcp(void *data) + * + * The trampoline will populate a dt_dctx_t struct and then call the function + * that implements the compiled D clause. It returns the value that it gets + * back from that function. + */ +static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) +{ + dt_irlist_t *dlp = &pcb->pcb_ir; + dt_probe_t *prp = pcb->pcb_probe; + dt_probe_t *uprp = pcb->pcb_parent_probe; + int direction, have_iphdr; + int skarg = 0, skbarg = 1, tcparg = 0; + int skarg_maybe_null; + int skstate = 0; + + /* + * We construct the tcp::: probe arguments as + * follows: + * args[0] = skb + * args[1] = sk + * args[2] = ip_hdr(skb) [if available] + * args[3] = sk [struct tcp_sock *] + * args[4] = tcp_hdr(skb) + * args[5] = sk->sk_state + * args[6] = sk->sk_state + * args[7] = NET_PROBE_INBOUND (0x1) | NET_PROBE_OUTBOUND (0x0) + */ + + if (strcmp(prp->desc->prb, "state-change") == 0) { + int newstatearg; + int skip_state = 0; + int check_proto = IPPROTO_TCP; + + /* For pre-6.14 kernels, inet_sock_state_change() to + * TCP_SYN_RCV is broken in that the cloned socket has + * not yet copied info of interest like addresses, ports. + * This is fixed in 6.14 via + * + * commit a3a128f611a965fddf8a02dd45716f96e0738e00 + * Author: Eric Dumazet + * Date: Wed Feb 12 13:13:28 2025 +0000 + * + * inet: consolidate inet_csk_clone_lock() + * + * To work around this we trace inet_csk_clone_lock and + * use the reqsk (arg1) as the means to populate the + * struct tcpinfo. We need then to explicitly set the + * state to TCP_SYN_RCV and also skip the case where + * inet_sock_set_state() specifies TCP_SYN_RCV otherwise + * we will get a probe double-firing. + */ + if (strcmp(uprp->desc->fun, "inet_csk_clone_lock") == 0) { + skarg = 1; + newstatearg = 2; + check_proto = 0; + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(2), + BPF_TCP_SYN_RECV)); + } else if (strcmp(uprp->desc->fun, "tcp_time_wait") == 0) { + skarg = 0; + newstatearg = 1; + } else { + skarg = 0; + newstatearg = 2; + skip_state = BPF_TCP_SYN_RECV; + } + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(skarg))); + emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_6, 0, exitlbl)); + /* check it is a TCP socket */ + if (check_proto) { + dt_cg_get_member(pcb, "struct sock", BPF_REG_6, + "sk_protocol"); + emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, + IPPROTO_TCP, exitlbl)); + } + /* save sk */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(skarg))); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(3), BPF_REG_6)); + + /* save new state */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(newstatearg))); + if (skip_state) { + emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_6, skip_state, + exitlbl)); + } + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(6), BPF_REG_6)); + + /* save sk */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(3))); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_6)); + + /* save empty args */ + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(0), 0)); + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(2), 0)); + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(4), 0)); + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(5), 0)); + + /* NET_PROBE_STATE */ + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(7), + NET_PROBE_STATE)); + return 0; + } + + if (strcmp(prp->desc->prb, "accept-established") == 0) { + direction = NET_PROBE_OUTBOUND; + have_iphdr = 1; + /* skb in arg2 not arg1 */ + skbarg = 2; + skarg_maybe_null = 0; + /* ensure arg1 is BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(1))); + emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_6, + BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB, + exitlbl)); + } else if (strcmp(prp->desc->prb, "receive") == 0 || + strcmp(prp->desc->prb, "accept-refused") == 0) { + direction = NET_PROBE_INBOUND; + have_iphdr = 1; + if (strcmp(uprp->desc->fun, "tcp_v4_send_reset") == 0 || + strcmp(uprp->desc->fun, "tcp_v6_send_reset") == 0) + skarg_maybe_null = 1; + else + skarg_maybe_null = 0; + } else if (strcmp(prp->desc->prb, "connect-established") == 0) { + direction = NET_PROBE_INBOUND; + have_iphdr = 1; + skarg_maybe_null = 0; + } else if (strcmp(prp->desc->prb, "connect-refused") == 0) { + direction = NET_PROBE_INBOUND; + have_iphdr = 1; + skarg_maybe_null = 0; + skstate = BPF_TCP_SYN_SENT; + } else { + direction = NET_PROBE_OUTBOUND; + if (strcmp(uprp->desc->fun, "ip_send_unicast_reply") == 0) { + /* NULL sk in arg1 not arg2 (we dont want ctl_sk) */ + skarg = 1; + /* skb in arg2 not arg1 */ + skbarg = 2; + have_iphdr = 1; + /* tcp hdr in ip_reply_arg * */ + tcparg = 6; + skarg_maybe_null = 1; + } else if (strcmp(uprp->desc->fun, "ip_build_and_send_pkt") == 0) { + skarg = 1; + skbarg = 0; + have_iphdr = 0; + skarg_maybe_null = 1; + } else if (strcmp(prp->desc->prb, "connect-request") == 0) { + skstate = BPF_TCP_SYN_SENT; + have_iphdr = 0; + skarg_maybe_null = 0; + } else { + have_iphdr = 0; + skarg_maybe_null = 0; + } + } + + /* first save sk to args[3]; this avoids overwriting it when we + * populate args[0,1] below. + */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(skarg))); + /* only allow NULL sk for ip_send_unicast_reply() */ + if (!skarg_maybe_null) + emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_6, 0, exitlbl)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(3), BPF_REG_6)); + + /* then save skb to args[0] */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(skbarg))); + emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_6, 0, exitlbl)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(0), BPF_REG_6)); + + /* next save sk to args[1] now that we have skb in args[0] */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(3))); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_6)); + + /* + * ip_hdr(skb) = + * skb_network_header(skb) = (include/linux/ip.h) + * skb->head + skb->network_header (include/linux/skbuff.h) + */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(0))); + dt_cg_get_member(pcb, "struct sk_buff", BPF_REG_6, "head"); + if (have_iphdr) + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(2), BPF_REG_0)); + else + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(2), 0)); + + if (have_iphdr) { + dt_cg_get_member(pcb, "struct sk_buff", BPF_REG_6, + "network_header"); + emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_7, DMST_ARG(2), BPF_REG_0)); + } + /* + * tcp_hdr(skb) = + * skb_transport_header(skb) = (include/linux/ip.h) + * skb->head + skb->transport_header (include/linux/skbuff.h) + */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(tcparg))); + if (tcparg) { + /* struct ip_reply_arg * has a kvec containing the tcp header */ + dt_cg_get_member(pcb, "struct kvec", BPF_REG_6, "iov_base"); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(4), BPF_REG_0)); + } else { + dt_cg_get_member(pcb, "struct sk_buff", BPF_REG_6, "head"); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(4), BPF_REG_0)); + dt_cg_get_member(pcb, "struct sk_buff", BPF_REG_6, + "transport_header"); + emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_7, DMST_ARG(4), BPF_REG_0)); + } + + if (!skarg_maybe_null) { + /* save sk state */ + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_7, DMST_ARG(3))); + dt_cg_get_member(pcb, "struct sock_common", BPF_REG_6, + "skc_state"); + /* ensure sk state - if specified - is what we expect */ + if (skstate) + emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, skstate, + exitlbl)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(5), BPF_REG_0)); + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(6), BPF_REG_0)); + } + emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(7), direction)); + + return 0; +} + +dt_provimpl_t dt_tcp = { + .name = prvname, + .prog_type = BPF_PROG_TYPE_UNSPEC, + .populate = &populate, + .enable = &dt_sdt_enable, + .load_prog = &dt_bpf_prog_load, + .trampoline = &trampoline, + .probe_info = &dt_sdt_probe_info, + .destroy = &dt_sdt_destroy, +}; diff --git a/libdtrace/dt_provider.c b/libdtrace/dt_provider.c index 0c621197..798e67ee 100644 --- a/libdtrace/dt_provider.c +++ b/libdtrace/dt_provider.c @@ -41,6 +41,7 @@ const dt_provimpl_t *dt_providers[] = { &dt_sched, &dt_sdt, &dt_syscall, + &dt_tcp, &dt_uprobe, &dt_usdt, NULL diff --git a/libdtrace/dt_provider.h b/libdtrace/dt_provider.h index 59a8d62e..4db89b45 100644 --- a/libdtrace/dt_provider.h +++ b/libdtrace/dt_provider.h @@ -87,6 +87,7 @@ extern dt_provimpl_t dt_rawtp; extern dt_provimpl_t dt_sched; extern dt_provimpl_t dt_sdt; extern dt_provimpl_t dt_syscall; +extern dt_provimpl_t dt_tcp; extern dt_provimpl_t dt_uprobe; extern dt_provimpl_t dt_usdt; diff --git a/libdtrace/ip.d b/libdtrace/ip.d index f8b77f12..d59bb436 100644 --- a/libdtrace/ip.d +++ b/libdtrace/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/libdtrace/net.d b/libdtrace/net.d index 6ac34287..45b5cba3 100644 --- a/libdtrace/net.d +++ b/libdtrace/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/libdtrace/tcp.d b/libdtrace/tcp.d index 54e310cb..d4beea87 100644 --- a/libdtrace/tcp.d +++ b/libdtrace/tcp.d @@ -8,7 +8,6 @@ #pragma D depends_on module vmlinux #pragma D depends_on library net.d #pragma D depends_on provider ip -#pragma D depends_on provider tcp inline int TH_FIN = 0x01; inline int TH_SYN = 0x02; @@ -60,7 +59,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,13 +110,16 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; tcp_hdr = (uintptr_t)T; }; +inline int tcp_fullsock[struct tcp_sock *sk] = + (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED && + ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT); /* * In the main we simply translate from the "struct [tcp_]sock *" to * a tcpsinfo_t *. However there are a few exceptions: @@ -158,47 +160,45 @@ translator tcpsinfo_t < struct tcp_sock *T > { ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] && ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3]) : 0; - tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ? + tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 && + tcp_fullsock[T] ? ntohs(((struct inet_sock *)T)->inet_sport) : (T && ((struct inet_sock *)T)->inet_sport == 0) ? - ntohs(((struct sock *)T)->__sk_common.skc_num) : + ((struct sock *)T)->__sk_common.skc_num : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +229,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; -- 2.39.3 From alan.maguire at oracle.com Tue Jun 10 13:58:13 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Tue, 10 Jun 2025 14:58:13 +0100 Subject: [DTrace-devel] [PATCH v2 4/4] dtrace: sync dlibs with tcp.d, ip.d and net.d changes In-Reply-To: <20250610135813.15746-1-alan.maguire@oracle.com> References: <20250610135813.15746-1-alan.maguire@oracle.com> Message-ID: <20250610135813.15746-5-alan.maguire@oracle.com> As part of adding tcp provider tcp.d, ip.d and net.d were changed; sync the version-specific dlibs. Signed-off-by: Alan Maguire --- dlibs/aarch64/5.14/ip.d | 1 - dlibs/aarch64/5.14/net.d | 6 ++++- dlibs/aarch64/5.14/tcp.d | 52 ++++++++++++++++++++++------------------ dlibs/aarch64/5.16/ip.d | 1 - dlibs/aarch64/5.16/net.d | 6 ++++- dlibs/aarch64/5.16/tcp.d | 52 ++++++++++++++++++++++------------------ dlibs/aarch64/6.1/ip.d | 1 - dlibs/aarch64/6.1/net.d | 6 ++++- dlibs/aarch64/6.1/tcp.d | 52 ++++++++++++++++++++++------------------ dlibs/aarch64/6.10/ip.d | 1 - dlibs/aarch64/6.10/net.d | 6 ++++- dlibs/aarch64/6.10/tcp.d | 52 ++++++++++++++++++++++------------------ dlibs/x86_64/5.14/ip.d | 1 - dlibs/x86_64/5.14/net.d | 6 ++++- dlibs/x86_64/5.14/tcp.d | 52 ++++++++++++++++++++++------------------ dlibs/x86_64/5.16/ip.d | 1 - dlibs/x86_64/5.16/net.d | 6 ++++- dlibs/x86_64/5.16/tcp.d | 52 ++++++++++++++++++++++------------------ dlibs/x86_64/6.1/ip.d | 1 - dlibs/x86_64/6.1/net.d | 6 ++++- dlibs/x86_64/6.1/tcp.d | 52 ++++++++++++++++++++++------------------ dlibs/x86_64/6.10/ip.d | 1 - dlibs/x86_64/6.10/net.d | 6 ++++- dlibs/x86_64/6.10/tcp.d | 52 ++++++++++++++++++++++------------------ 24 files changed, 272 insertions(+), 200 deletions(-) diff --git a/dlibs/aarch64/5.14/ip.d b/dlibs/aarch64/5.14/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/aarch64/5.14/ip.d +++ b/dlibs/aarch64/5.14/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/aarch64/5.14/net.d b/dlibs/aarch64/5.14/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/aarch64/5.14/net.d +++ b/dlibs/aarch64/5.14/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/aarch64/5.14/tcp.d b/dlibs/aarch64/5.14/tcp.d index 54e310cb..d4beea87 100644 --- a/dlibs/aarch64/5.14/tcp.d +++ b/dlibs/aarch64/5.14/tcp.d @@ -8,7 +8,6 @@ #pragma D depends_on module vmlinux #pragma D depends_on library net.d #pragma D depends_on provider ip -#pragma D depends_on provider tcp inline int TH_FIN = 0x01; inline int TH_SYN = 0x02; @@ -60,7 +59,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,13 +110,16 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; tcp_hdr = (uintptr_t)T; }; +inline int tcp_fullsock[struct tcp_sock *sk] = + (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED && + ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT); /* * In the main we simply translate from the "struct [tcp_]sock *" to * a tcpsinfo_t *. However there are a few exceptions: @@ -158,47 +160,45 @@ translator tcpsinfo_t < struct tcp_sock *T > { ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] && ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3]) : 0; - tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ? + tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 && + tcp_fullsock[T] ? ntohs(((struct inet_sock *)T)->inet_sport) : (T && ((struct inet_sock *)T)->inet_sport == 0) ? - ntohs(((struct sock *)T)->__sk_common.skc_num) : + ((struct sock *)T)->__sk_common.skc_num : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +229,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/aarch64/5.16/ip.d b/dlibs/aarch64/5.16/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/aarch64/5.16/ip.d +++ b/dlibs/aarch64/5.16/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/aarch64/5.16/net.d b/dlibs/aarch64/5.16/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/aarch64/5.16/net.d +++ b/dlibs/aarch64/5.16/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/aarch64/5.16/tcp.d b/dlibs/aarch64/5.16/tcp.d index 54e310cb..d4beea87 100644 --- a/dlibs/aarch64/5.16/tcp.d +++ b/dlibs/aarch64/5.16/tcp.d @@ -8,7 +8,6 @@ #pragma D depends_on module vmlinux #pragma D depends_on library net.d #pragma D depends_on provider ip -#pragma D depends_on provider tcp inline int TH_FIN = 0x01; inline int TH_SYN = 0x02; @@ -60,7 +59,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,13 +110,16 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; tcp_hdr = (uintptr_t)T; }; +inline int tcp_fullsock[struct tcp_sock *sk] = + (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED && + ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT); /* * In the main we simply translate from the "struct [tcp_]sock *" to * a tcpsinfo_t *. However there are a few exceptions: @@ -158,47 +160,45 @@ translator tcpsinfo_t < struct tcp_sock *T > { ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] && ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3]) : 0; - tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ? + tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 && + tcp_fullsock[T] ? ntohs(((struct inet_sock *)T)->inet_sport) : (T && ((struct inet_sock *)T)->inet_sport == 0) ? - ntohs(((struct sock *)T)->__sk_common.skc_num) : + ((struct sock *)T)->__sk_common.skc_num : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +229,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/aarch64/6.1/ip.d b/dlibs/aarch64/6.1/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/aarch64/6.1/ip.d +++ b/dlibs/aarch64/6.1/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/aarch64/6.1/net.d b/dlibs/aarch64/6.1/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/aarch64/6.1/net.d +++ b/dlibs/aarch64/6.1/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/aarch64/6.1/tcp.d b/dlibs/aarch64/6.1/tcp.d index 54e310cb..d4beea87 100644 --- a/dlibs/aarch64/6.1/tcp.d +++ b/dlibs/aarch64/6.1/tcp.d @@ -8,7 +8,6 @@ #pragma D depends_on module vmlinux #pragma D depends_on library net.d #pragma D depends_on provider ip -#pragma D depends_on provider tcp inline int TH_FIN = 0x01; inline int TH_SYN = 0x02; @@ -60,7 +59,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,13 +110,16 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; tcp_hdr = (uintptr_t)T; }; +inline int tcp_fullsock[struct tcp_sock *sk] = + (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED && + ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT); /* * In the main we simply translate from the "struct [tcp_]sock *" to * a tcpsinfo_t *. However there are a few exceptions: @@ -158,47 +160,45 @@ translator tcpsinfo_t < struct tcp_sock *T > { ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] && ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3]) : 0; - tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ? + tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 && + tcp_fullsock[T] ? ntohs(((struct inet_sock *)T)->inet_sport) : (T && ((struct inet_sock *)T)->inet_sport == 0) ? - ntohs(((struct sock *)T)->__sk_common.skc_num) : + ((struct sock *)T)->__sk_common.skc_num : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +229,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/aarch64/6.10/ip.d b/dlibs/aarch64/6.10/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/aarch64/6.10/ip.d +++ b/dlibs/aarch64/6.10/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/aarch64/6.10/net.d b/dlibs/aarch64/6.10/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/aarch64/6.10/net.d +++ b/dlibs/aarch64/6.10/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/aarch64/6.10/tcp.d b/dlibs/aarch64/6.10/tcp.d index 54e310cb..d4beea87 100644 --- a/dlibs/aarch64/6.10/tcp.d +++ b/dlibs/aarch64/6.10/tcp.d @@ -8,7 +8,6 @@ #pragma D depends_on module vmlinux #pragma D depends_on library net.d #pragma D depends_on provider ip -#pragma D depends_on provider tcp inline int TH_FIN = 0x01; inline int TH_SYN = 0x02; @@ -60,7 +59,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,13 +110,16 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; tcp_hdr = (uintptr_t)T; }; +inline int tcp_fullsock[struct tcp_sock *sk] = + (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED && + ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT); /* * In the main we simply translate from the "struct [tcp_]sock *" to * a tcpsinfo_t *. However there are a few exceptions: @@ -158,47 +160,45 @@ translator tcpsinfo_t < struct tcp_sock *T > { ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] && ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3]) : 0; - tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ? + tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 && + tcp_fullsock[T] ? ntohs(((struct inet_sock *)T)->inet_sport) : (T && ((struct inet_sock *)T)->inet_sport == 0) ? - ntohs(((struct sock *)T)->__sk_common.skc_num) : + ((struct sock *)T)->__sk_common.skc_num : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +229,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/x86_64/5.14/ip.d b/dlibs/x86_64/5.14/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/x86_64/5.14/ip.d +++ b/dlibs/x86_64/5.14/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/x86_64/5.14/net.d b/dlibs/x86_64/5.14/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/x86_64/5.14/net.d +++ b/dlibs/x86_64/5.14/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/x86_64/5.14/tcp.d b/dlibs/x86_64/5.14/tcp.d index 54e310cb..d4beea87 100644 --- a/dlibs/x86_64/5.14/tcp.d +++ b/dlibs/x86_64/5.14/tcp.d @@ -8,7 +8,6 @@ #pragma D depends_on module vmlinux #pragma D depends_on library net.d #pragma D depends_on provider ip -#pragma D depends_on provider tcp inline int TH_FIN = 0x01; inline int TH_SYN = 0x02; @@ -60,7 +59,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,13 +110,16 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; tcp_hdr = (uintptr_t)T; }; +inline int tcp_fullsock[struct tcp_sock *sk] = + (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED && + ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT); /* * In the main we simply translate from the "struct [tcp_]sock *" to * a tcpsinfo_t *. However there are a few exceptions: @@ -158,47 +160,45 @@ translator tcpsinfo_t < struct tcp_sock *T > { ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] && ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3]) : 0; - tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ? + tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 && + tcp_fullsock[T] ? ntohs(((struct inet_sock *)T)->inet_sport) : (T && ((struct inet_sock *)T)->inet_sport == 0) ? - ntohs(((struct sock *)T)->__sk_common.skc_num) : + ((struct sock *)T)->__sk_common.skc_num : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +229,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/x86_64/5.16/ip.d b/dlibs/x86_64/5.16/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/x86_64/5.16/ip.d +++ b/dlibs/x86_64/5.16/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/x86_64/5.16/net.d b/dlibs/x86_64/5.16/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/x86_64/5.16/net.d +++ b/dlibs/x86_64/5.16/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/x86_64/5.16/tcp.d b/dlibs/x86_64/5.16/tcp.d index 54e310cb..d4beea87 100644 --- a/dlibs/x86_64/5.16/tcp.d +++ b/dlibs/x86_64/5.16/tcp.d @@ -8,7 +8,6 @@ #pragma D depends_on module vmlinux #pragma D depends_on library net.d #pragma D depends_on provider ip -#pragma D depends_on provider tcp inline int TH_FIN = 0x01; inline int TH_SYN = 0x02; @@ -60,7 +59,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,13 +110,16 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; tcp_hdr = (uintptr_t)T; }; +inline int tcp_fullsock[struct tcp_sock *sk] = + (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED && + ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT); /* * In the main we simply translate from the "struct [tcp_]sock *" to * a tcpsinfo_t *. However there are a few exceptions: @@ -158,47 +160,45 @@ translator tcpsinfo_t < struct tcp_sock *T > { ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] && ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3]) : 0; - tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ? + tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 && + tcp_fullsock[T] ? ntohs(((struct inet_sock *)T)->inet_sport) : (T && ((struct inet_sock *)T)->inet_sport == 0) ? - ntohs(((struct sock *)T)->__sk_common.skc_num) : + ((struct sock *)T)->__sk_common.skc_num : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +229,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/x86_64/6.1/ip.d b/dlibs/x86_64/6.1/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/x86_64/6.1/ip.d +++ b/dlibs/x86_64/6.1/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/x86_64/6.1/net.d b/dlibs/x86_64/6.1/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/x86_64/6.1/net.d +++ b/dlibs/x86_64/6.1/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/x86_64/6.1/tcp.d b/dlibs/x86_64/6.1/tcp.d index 54e310cb..d4beea87 100644 --- a/dlibs/x86_64/6.1/tcp.d +++ b/dlibs/x86_64/6.1/tcp.d @@ -8,7 +8,6 @@ #pragma D depends_on module vmlinux #pragma D depends_on library net.d #pragma D depends_on provider ip -#pragma D depends_on provider tcp inline int TH_FIN = 0x01; inline int TH_SYN = 0x02; @@ -60,7 +59,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,13 +110,16 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; tcp_hdr = (uintptr_t)T; }; +inline int tcp_fullsock[struct tcp_sock *sk] = + (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED && + ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT); /* * In the main we simply translate from the "struct [tcp_]sock *" to * a tcpsinfo_t *. However there are a few exceptions: @@ -158,47 +160,45 @@ translator tcpsinfo_t < struct tcp_sock *T > { ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] && ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3]) : 0; - tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ? + tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 && + tcp_fullsock[T] ? ntohs(((struct inet_sock *)T)->inet_sport) : (T && ((struct inet_sock *)T)->inet_sport == 0) ? - ntohs(((struct sock *)T)->__sk_common.skc_num) : + ((struct sock *)T)->__sk_common.skc_num : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +229,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; diff --git a/dlibs/x86_64/6.10/ip.d b/dlibs/x86_64/6.10/ip.d index f8b77f12..d59bb436 100644 --- a/dlibs/x86_64/6.10/ip.d +++ b/dlibs/x86_64/6.10/ip.d @@ -51,7 +51,6 @@ inline int TCP_MIN_HEADER_LENGTH = 20; * to the net namespace (nd_net in struct net_device). */ typedef uint64_t netstackid_t; -typedef __be32 ipaddr_t; typedef struct in6_addr in6_addr_t; /* diff --git a/dlibs/x86_64/6.10/net.d b/dlibs/x86_64/6.10/net.d index 6ac34287..45b5cba3 100644 --- a/dlibs/x86_64/6.10/net.d +++ b/dlibs/x86_64/6.10/net.d @@ -25,9 +25,13 @@ typedef struct conninfo { string ci_protocol; /* protocol (ipv4, ipv6, etc) */ } conninfo_t; +typedef __be32 ipaddr_t; + /* * We use these values to determine if a probe point is associated - * with sending (outbound) or receiving (inbound). + * with sending (outbound) or receiving (inbound) or a state-related + * probe (i.e. neither in our outbound). */ inline int NET_PROBE_OUTBOUND = 0x00; inline int NET_PROBE_INBOUND = 0x01; +inline int NET_PROBE_STATE = 0x02; diff --git a/dlibs/x86_64/6.10/tcp.d b/dlibs/x86_64/6.10/tcp.d index 54e310cb..d4beea87 100644 --- a/dlibs/x86_64/6.10/tcp.d +++ b/dlibs/x86_64/6.10/tcp.d @@ -8,7 +8,6 @@ #pragma D depends_on module vmlinux #pragma D depends_on library net.d #pragma D depends_on provider ip -#pragma D depends_on provider tcp inline int TH_FIN = 0x01; inline int TH_SYN = 0x02; @@ -60,7 +59,7 @@ typedef struct tcpinfo { uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ - uint8_t tcp_flags; /* flags */ + uint16_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ @@ -111,13 +110,16 @@ translator tcpinfo_t < struct tcphdr *T > { tcp_seq = T ? ntohl(T->seq) : 0; tcp_ack = T ? ntohl(T->ack_seq) : 0; tcp_offset = T ? (*(uint8_t *)(T + 12) & 0xf0) >> 2 : 0; - tcp_flags = T ? *(uint8_t *)(T + 13) : 0; + tcp_flags = T ? *((uint8_t *)T + 13) : 0; tcp_window = T ? ntohs(T->window) : 0; tcp_checksum = T ? ntohs(T->check) : 0; tcp_urgent = T ? ntohs(T->urg_ptr) : 0; tcp_hdr = (uintptr_t)T; }; +inline int tcp_fullsock[struct tcp_sock *sk] = + (((struct sock_common *)sk)->skc_state != TCP_STATE_SYN_RECEIVED && + ((struct sock_common *)sk)->skc_state != TCP_STATE_TIME_WAIT); /* * In the main we simply translate from the "struct [tcp_]sock *" to * a tcpsinfo_t *. However there are a few exceptions: @@ -158,47 +160,45 @@ translator tcpsinfo_t < struct tcp_sock *T > { ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_daddr)[2] && ((uint32_t *)&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr)[3]) : 0; - tcps_lport = (T && ((struct inet_sock *)T)->inet_sport != 0) ? + tcps_lport = T && ((struct inet_sock *)T)->inet_sport != 0 && + tcp_fullsock[T] ? ntohs(((struct inet_sock *)T)->inet_sport) : (T && ((struct inet_sock *)T)->inet_sport == 0) ? - ntohs(((struct sock *)T)->__sk_common.skc_num) : + ((struct sock *)T)->__sk_common.skc_num : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->dest : ((struct tcphdr *)arg4)->source) : + ((struct tcphdr *)arg4)->dest : + ((struct tcphdr *)arg4)->source) : 0; tcps_rport = T && ((struct sock *)T)->__sk_common.skc_dport != 0 ? ntohs(((struct sock *)T)->__sk_common.skc_dport) : arg4 != NULL ? ntohs(arg7 == NET_PROBE_INBOUND ? - ((struct tcphdr *)arg4)->source : ((struct tcphdr *)arg4)->dest) : + ((struct tcphdr *)arg4)->source : + ((struct tcphdr *)arg4)->dest) : 0; tcps_laddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_rcv_saddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_rcv_saddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->daddr : &((struct iphdr *)arg2)->saddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->daddr : - &((struct ipv6hdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->daddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->daddr) : ""; tcps_raddr = T && ((struct sock *)T)->__sk_common.skc_family == AF_INET ? inet_ntoa(&((struct sock *)T)->__sk_common.skc_daddr) : T && ((struct sock *)T)->__sk_common.skc_family == AF_INET6 ? inet_ntoa6(&((struct sock *)T)->__sk_common.skc_v6_daddr) : - arg2 != NULL && (*(uint8_t *)arg2) >> 4 == 4 ? - inet_ntoa(arg7 == NET_PROBE_INBOUND ? - &((struct iphdr *)arg2)->saddr : &((struct iphdr *)arg2)->daddr) : - arg2 != NULL && *((uint8_t *)arg2) >> 4 == 6 ? - inet_ntoa6(arg7 == NET_PROBE_INBOUND ? - &((struct ipv6hdr *)arg2)->saddr : - &((struct ipv6hdr *)arg2)->daddr) : - ""; - tcps_state = arg6; + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 4 ? + inet_ntoa(&((struct iphdr *)arg2)->saddr) : + arg2 != NULL && (*(uint8_t *)arg2 >> 4) == 6 ? + inet_ntoa6(&((struct ipv6hdr *)arg2)->saddr) : + "__sk_common.skc_state : 0; tcps_iss = T ? T->snd_una - (uint32_t)T->bytes_acked : 0; tcps_suna = T ? T->snd_una : 0; @@ -229,3 +229,9 @@ translator tcpsinfo_t < struct tcp_sock *T > { translator tcplsinfo_t < int I > { tcps_state = I; }; + +/* For tracepoint, the last state is in the sock state, next passed as arg6 */ +#pragma D binding "1.6.3" translator +translator tcplsinfo_t < struct sock *S > { + tcps_state = S ? S->__sk_common.skc_state : 0; +}; -- 2.39.3 From eugene.loh at oracle.com Tue Jun 10 21:10:42 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Tue, 10 Jun 2025 17:10:42 -0400 Subject: [DTrace-devel] [PATCH] No uprobes on ARM autiasp instructions Message-ID: <20250610211042.20522-1-eugene.loh@oracle.com> From: Eugene Loh New compilers emit autiasp instructions much more liberally. A test like test/unittest/pid/tst.entry_off0.sh, which tries to put a probe on each instruction, may fail. Signed-off-by: Eugene Loh --- libdtrace/dt_pid.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index e2d4e540d..833e9b647 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -279,12 +279,17 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) nmatches++; } else if (glob) { -#if defined(__amd64) /* - * We need to step through the instructions to find their - * offsets. This is difficult on x86, which has variable - * instruction lengths. We invoke the disassembler in - * libopcodes. + * We need the instructions for two reasons: + * = On x86, instructions have varying lengths. So, + * to step through the instructions, we need to + * disassemble them to know what they are. + * We invoke the disassembler in libopcodes. + * (On ARM, we step through 4 bytes at a time.) + * = On both x86 and arm, we want to skip certain + * instructions. So, again, we need to know what they are. + */ + /* * * We look for the Elf pointer. It is already stored in * file_elf in file_info_t, but getting it back over here @@ -298,7 +303,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) GElf_Shdr shdr; Elf_Data *data; size_t shstrndx, off; - disassembler_ftype disasm; /* Set things up. */ fd = open(pp->dpp_fname, O_RDONLY); @@ -344,12 +348,14 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) /* Get the instructions. */ data = elf_getdata(scn, NULL); +#if defined(__amd64) /* * "Disassemble" instructions just to get the offsets. * * Unfortunately, libopcodes's disassembler() has a different * interface in binutils versions before 2.29. */ + disassembler_ftype disasm; #if defined(HAVE_DIS1) == defined(HAVE_DIS4) #error expect disassembler() to have 1 or else 4 arguments #endif @@ -390,6 +396,11 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) /* Newer kernels do not allow uprobes on "hlt" instructions. */ if ((unsigned int)disasm_info.buffer[off] == 0xf4) continue; +#else + /* On ARM, we cannot place uprobes on "autiasp" instructions. */ + if (*((unsigned int *)(data->d_buf + (sym.st_value + off - shdr.sh_addr))) + == 0xd50323bf) + continue; #endif snprintf(offstr, sizeof(offstr), "%lx", off); -- 2.43.5 From nick.alcock at oracle.com Fri Jun 13 14:10:17 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:10:17 +0100 Subject: [DTrace-devel] [PATCH] test: Suppress some white space In-Reply-To: <20250609180647.4424-1-eugene.loh@oracle.com> (eugene loh's message of "Mon, 9 Jun 2025 14:06:47 -0400") References: <20250609180647.4424-1-eugene.loh@oracle.com> Message-ID: <87cyb7enqu.fsf@esperi.org.uk> On 9 Jun 2025, eugene loh spake thusly: > From: Eugene Loh > > The test suite turns pointers into "{ptr}" so that results > comparisons will not be sensitive to particular pointer offset > values. > > If these offsets change in width -- say, from 0xf0 to 0x100 -- > the amount of white space in the postprocessed output can change. > > Add additional postprocessing to a test that sometimes fails due > to this problem. Hmm... this would work for this test, but maybe we should change the {ptr} substitution in runtest.sh itself so that it gets this right in the general case? Something like diff --git a/runtest.sh b/runtest.sh index 156e7dec8a1c3..c5703a81bc6d4 100755 --- a/runtest.sh +++ b/runtest.sh @@ -509,7 +509,7 @@ postprocess() # TODO: may need adjustment or making optional if scripts emit hex # values which are not continuously variable. - sed -e '/^==[0-9][0-9]*== /!s,0x[0-9a-f][0-9a-f]*,{ptr},g' \ + sed -e '/^==[0-9][0-9]*== /!s,0x[0-9a-f][0-9a-f]*\([ \t]*\),{ptr}\1,g' \ -e 's,at BPF pc [1-9][0-9]*,at BPF pc NNN,' < $tmpdir/pp.out > $final return $retval might work. (Obviously the lines would no longer line up, but the number of spaces would remain the same as they were before the substitution.) Lots and lots of expected results would need regenerating after this, of course... -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:15:44 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:15:44 +0100 Subject: [DTrace-devel] [PATCH] test: Wait for output to flush out in enable_pid In-Reply-To: <20250608053620.15468-1-eugene.loh@oracle.com> (eugene loh's message of "Sun, 8 Jun 2025 01:36:20 -0400") References: <20250608053620.15468-1-eugene.loh@oracle.com> Message-ID: <878qlvenhr.fsf@esperi.org.uk> On 8 Jun 2025, eugene loh told this: > From: Eugene Loh > > Our luck with this test has been quite good, but it sometimes fails > to show its last lines of output. That is, we send a USR1 to the > trigger processes to set off the final output and we immediately > cat the output files. If there is any delay, the last output will > be missing. > > Add a short delay so that the last output will be seen. Unavoidable if it's structured this way, but if you hit them with a USR2 and caught USR2 and had that do the same output as USR1 and then exit(), and did a wait(1) for both of them, you could avoid this delay. -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:19:02 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:19:02 +0100 Subject: [DTrace-devel] [PATCH] test: Make the USDT "only enabled" test more stringent In-Reply-To: <20250603203532.20743-1-eugene.loh@oracle.com> (eugene loh's message of "Tue, 3 Jun 2025 16:35:32 -0400") References: <20250603203532.20743-1-eugene.loh@oracle.com> Message-ID: <871prnenc9.fsf@esperi.org.uk> On 3 Jun 2025, eugene loh said: > From: Eugene Loh > > What if a program has an is-enabled probe without the corresponding > parent probe? It should at least compile, and we test that. > > Add more checks to the test: > - the is-enabled branch is not taken when run without dtrace > - the parent USDT probe is listed with "dtrace -l" > - the is-enabled branch is not taken even when run with dtrace > if the parent probe is not enabled > - the is-enabled branch is taken when run with dtrace > and the parent probe is enabled; however, the parent probe > does not fire since it is not in the test trigger Nice! > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock From nick.alcock at oracle.com Fri Jun 13 14:23:21 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:23:21 +0100 Subject: [DTrace-devel] [PATCH] Revert "dt_pid: pid grabs should be shortlived" In-Reply-To: <20250522181016.27661-1-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:10:16 -0400") References: <20250522181016.27661-1-eugene.loh@oracle.com> Message-ID: <87wm9fd8km.fsf@esperi.org.uk> On 22 May 2025, eugene loh verbalised: > From: Eugene Loh > > Commit 4aec5c9931eb ("dt_pid: pid grabs should be shortlived") made > grabs short-lived. No test cases show the utility of this patch. > Meanwhile, the patch causes roughly a dozen tests to fail on OL9 > when the test suite is started remotely using ssh, closing ttys. The I think this is a consequence of another bug (Psystem_daemon() was failing to detect that systemd was running correctly on systemd v2 systems, and we were falling back to the old approach, which is indeed going to conclude that processes in system groups without controlling terminals or associated TTYs are system daemons). I have a fix for this detection failure under test now and will post it shortly. -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:33:33 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:33:33 +0100 Subject: [DTrace-devel] [PATCH 01/14] Fix stack-skip counts for caller and stackdepth In-Reply-To: <20250522180118.27343-1-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:05 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> Message-ID: <87sek3d83m.fsf@esperi.org.uk> On 22 May 2025, eugene loh told this: > From: Eugene Loh > > Apparently, when we call the BPF get_stack() helper function, > it generally knows how many frames to skip to get the real kernel > stack. For fentry/fexit, however, this is apparently not the case, > and commit bc65cb44d > ("cg: allow providers to specify a skip count for stack retrieval") > added the ability to skip frames for fentry/fexit probes. > > When this "skip" is needed, however, it must must be even deeper > when we descend further frames, such as when we call dt_bpf_*() > precompiled functions. Ack. > Add this support for dt_bpf_caller() and dt_bpf_stackdepth(). > That is, if there are stack-skip frames, skip yet one more frame > when inside a bpf/get_bvar.c function. The general approach here seems sound, but this confuses me. Is the assumption that if the skip is not needed, get_stack() will itself know how many frames to skip, and will skip dt_dt_bvar_caller() for you? (So a zero skip is actually a "the system knows", and a nonzero skip causes the system to not skip anything, so you have to do all the skipping yourself? This behaviour is not documented in bpf_get_stack()'s documentation, which absolutely does not mean it doesn't do it...) > Note that we declare the skip count volatile. The compiler might > optimize code that uses the STACK_SKIP value, but we will subsequently > perform relocations that adjust this value. ... why doesn't this apply to every other extern global variable in get_bvar()? They're all similarly relocated... > Signed-off-by: Eugene Loh > --- > bpf/get_bvar.c | 17 ++++++++++++++--- > 1 file changed, 14 insertions(+), 3 deletions(-) > > diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c > index 9625e764e..99a6503d5 100644 > --- a/bpf/get_bvar.c > +++ b/bpf/get_bvar.c > @@ -53,12 +53,17 @@ noinline uint64_t dt_bvar_args(const dt_dctx_t *dctx, uint32_t idx) > > noinline uint64_t dt_bvar_caller(const dt_dctx_t *dctx) > { > - uint64_t buf[2] = { 0, }; > + uint64_t buf[3] = { 0, }; > + volatile uint64_t > + skip = (uint64_t)(&STACK_SKIP); > > if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), > - (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK) < 0) > + skip & BPF_F_SKIP_FIELD_MASK) < 0) > return 0; > > + /* If we had to skip any frames, account for the dt_bvar_caller() frame. */ > + if (skip) > + return buf[2]; > return buf[1]; > } > > @@ -203,9 +208,11 @@ 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; > + volatile uint64_t > + skip = (uint64_t)(&STACK_SKIP); > > retv = bpf_get_stack(dctx->ctx, buf, bufsiz, > - (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK); > + skip & BPF_F_SKIP_FIELD_MASK); > if (retv < 0) > return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); > > @@ -217,7 +224,11 @@ noinline uint64_t dt_bvar_stackdepth(const dt_dctx_t *dctx) > * 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. > + * > + * If we had to skip any frames, account for the dt_bvar_stackdepth() frame. > */ > + if (skip) > + return retv / sizeof(uint64_t) - 1; > return retv / sizeof(uint64_t); > } -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:35:02 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:35:02 +0100 Subject: [DTrace-devel] [PATCH 02/14] Add stack-skip frame count for rawtp provider In-Reply-To: <20250522180118.27343-2-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:06 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-2-eugene.loh@oracle.com> Message-ID: <87o6urd815.fsf@esperi.org.uk> On 22 May 2025, eugene loh outgrape: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock (looking back, 4 is the right figure. If it's wrong, the tests will tell us, anyway -- presumably we hope that the underlying bug is fixed before it changes in the future and requires us to make this a per-kernel-release value...) -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:35:32 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:35:32 +0100 Subject: [DTrace-devel] [PATCH 03/14] Test: remove unnecessary "unstable" tag In-Reply-To: <20250522180118.27343-3-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:07 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-3-eugene.loh@oracle.com> Message-ID: <87jz5fd80b.fsf@esperi.org.uk> On 22 May 2025, eugene loh spake thusly: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:40:55 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:40:55 +0100 Subject: [DTrace-devel] [PATCH 04/14] Test: caller and stackdepth tests for fbt provider In-Reply-To: <20250522180118.27343-4-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:08 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-4-eugene.loh@oracle.com> Message-ID: <87cyb7d7rc.fsf@esperi.org.uk> On 22 May 2025, eugene loh uttered the following: > From: Eugene Loh > > We will introduce a set of tests for the caller and stackdepth > built-in variables for a wide selection of providers. > > For the caller test, we will essentially call > stack(2); > sym(caller); > and then compare the caller to the second stack frame using > the new script check_caller_to_stack2.awk. > > For the stackdepth test, we will essentially call > printf("%d\n", stackdepth); > stack(); > and then compare the stackdepth to the reported frames using > the new script check_stackdepth_to_stack.awk. > > In this patch, introduce tests for the fbt provider, along with > the support scripts they need. Subsequent patches will handle > other providers. > > The old tst.caller2.d and tst.stackdepth2.d, which tested fbt, > become obsolete. Remove them. Nice! My only caveat (easily fixed) is that the old tests had header comments saying what they were testing, while the new ones don't. (Yes, the awk scripts do make it clearer, but still...) > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:42:12 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:42:12 +0100 Subject: [DTrace-devel] [PATCH 05/14] Test: caller and stackdepth tests for dtrace provider In-Reply-To: <20250522180118.27343-5-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:09 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-5-eugene.loh@oracle.com> Message-ID: <878qlvd7p7.fsf@esperi.org.uk> On 22 May 2025, eugene loh said: > From: Eugene Loh > > Also, a few old tests, which tested caller and stackdepth using the > dtrace provider, are now superfluous given the new, provider-named > tests. The old tests were extremely lenient -- e.g., simply > checking that these built-in variables were not -1, even though > both variables are unsigned anyhow! > > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock (with the same comments regarding the old tests having a description of what they were testing, and could the new ones do the same?) -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:45:23 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:45:23 +0100 Subject: [DTrace-devel] [PATCH 06/14] Test: caller and stackdepth tests for rawtp provider In-Reply-To: <20250522180118.27343-6-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:10 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-6-eugene.loh@oracle.com> Message-ID: <874iwjd7jw.fsf@esperi.org.uk> On 22 May 2025, eugene loh uttered the following: > From: Eugene Loh > > Also, add skip_rawtp_old.x, to skip rawtp testing on older kernels > for the reasons described in the file. > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:48:54 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:48:54 +0100 Subject: [DTrace-devel] [PATCH 07/14] Test: caller and stackdepth tests for cpc provider In-Reply-To: <20250522180118.27343-7-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:11 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-7-eugene.loh@oracle.com> Message-ID: <87zfebbstl.fsf@esperi.org.uk> On 22 May 2025, eugene loh outgrape: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock > +cpc:::cpu_clock-all-100000000 1/10th of a second: seems legit. (But having it use nanoseconds makes probe names hard to read! Yes, I know we have no choice here.) -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:51:18 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:51:18 +0100 Subject: [DTrace-devel] [PATCH 08/14] Test: caller and stackdepth tests for ip provider In-Reply-To: <20250522180118.27343-8-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:12 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-8-eugene.loh@oracle.com> Message-ID: <87v7ozbspl.fsf@esperi.org.uk> On 22 May 2025, eugene loh spake thusly: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock with the microscopic caveat below. > diff --git a/test/unittest/variables/bvar/perlping.pl b/test/unittest/variables/bvar/perlping.pl > new file mode 100755 > index 000000000..97c9b09e9 > --- /dev/null > +++ b/test/unittest/variables/bvar/perlping.pl > @@ -0,0 +1,8 @@ > +#!/usr/bin/perl -w > +# Oracle Linux DTrace. > +# Copyright (c) 2016, 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. > +use Net::Ping; > +my $p = Net::Ping->new(${ARGV[0]}, 5, 56); > +$p->ping(${ARGV[1]}); Is there some reason we can't just use $testdir/../../ip/perlping.pl and avoid duplicating this? -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:52:13 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:52:13 +0100 Subject: [DTrace-devel] [PATCH 09/14] Test: caller and stackdepth tests for profile provider In-Reply-To: <20250522180118.27343-9-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:13 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-9-eugene.loh@oracle.com> Message-ID: <87qzznbso2.fsf@esperi.org.uk> On 22 May 2025, eugene loh verbalised: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock (usual caveats regarding comments saying what these tests are doing...) -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:52:39 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:52:39 +0100 Subject: [DTrace-devel] [PATCH 10/14] Test: caller and stackdepth tests for sched provider In-Reply-To: <20250522180118.27343-10-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:14 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-10-eugene.loh@oracle.com> Message-ID: <87msabbsnc.fsf@esperi.org.uk> On 22 May 2025, eugene loh uttered the following: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:53:16 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:53:16 +0100 Subject: [DTrace-devel] [PATCH 11/14] Test: caller and stackdepth tests for proc provider In-Reply-To: <20250522180118.27343-11-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:15 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-11-eugene.loh@oracle.com> Message-ID: <87ikkzbsmb.fsf@esperi.org.uk> On 22 May 2025, eugene loh told this: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:54:31 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:54:31 +0100 Subject: [DTrace-devel] [PATCH 12/14] Test: caller and stackdepth tests for rawfbt provider In-Reply-To: <20250522180118.27343-12-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:16 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-12-eugene.loh@oracle.com> Message-ID: <87ecvnbsk8.fsf@esperi.org.uk> On 22 May 2025, eugene loh spake thusly: > From: Eugene Loh > > Signed-off-by: Eugene Loh I note the lack of any sort of skipping on older kernels. Do the concerns about older kernels not apply here? If not, and this was intentional... Reviewed-by: Nick Alcock -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:56:36 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:56:36 +0100 Subject: [DTrace-devel] [PATCH 13/14] Test: caller and stackdepth tests for io provider In-Reply-To: <20250522180118.27343-13-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:17 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-13-eugene.loh@oracle.com> Message-ID: <87a56bbsgr.fsf@esperi.org.uk> On 22 May 2025, eugene loh spake thusly: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock > --- /dev/null > +++ b/test/unittest/variables/bvar/tst.caller-io.sh > @@ -0,0 +1,37 @@ > +#!/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 > +nblocks=1024 > +filesize=$((1024*$nblocks)) > +fsoptions="defaults,atime,diratime,nosuid,nodev" > +iodir=$tmpdir/tst-caller-io.$$ > +tempfile=`mktemp -u -p $iodir` > + > +trap "umount $iodir; rmdir $iodir; rm -f $iodir.img" QUIT EXIT > + > +# create loopback file system We have quite a lot of these I/O-trigger filesystem things now (this is our sixth and seventh). Maybe we should think about refactoring the mount-and-mkfs-and-dd-and-umount bit out into shared code at some point... -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 14:57:48 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 15:57:48 +0100 Subject: [DTrace-devel] [PATCH 14/14] Test: caller and stackdepth tests for lockstat provider In-Reply-To: <20250522180118.27343-14-eugene.loh@oracle.com> (eugene loh's message of "Thu, 22 May 2025 14:01:18 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-14-eugene.loh@oracle.com> Message-ID: <875xgzbser.fsf@esperi.org.uk> On 22 May 2025, eugene loh spake thusly: > From: Eugene Loh > > Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock (I guess we can assume that as long as it has any trigger at all, it's going to be firing lockstats like mad.) -- NULL && (void) From nick.alcock at oracle.com Fri Jun 13 16:46:37 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Fri, 13 Jun 2025 17:46:37 +0100 Subject: [DTrace-devel] [PATCH] libproc: make Psystem_daemon() detect modern systemd properly Message-ID: <20250613164637.3110-1-nick.alcock@oracle.com> Psystem_daemon() is used when carrying out shortlived grabs to detect whether a process is too risky to carry out invasive grabs of (you wouldn't usually want to stop syslogd or, God forbid, try to ptrace PID 1, unless explicitly requested via -p: the process just coming up in routine probe firing is not enough). This has two code paths: a reliable one for systemd systems (which checks to see if the process is in the system slice, which contains precisely and only system daemons), and an unreliable one for other systems (which does the old Unix approach of consdering anything in the user uid range or with a TTY or with open standard FDs to TTYs to be not system daemons, and everything else to possibly be one). We were checking to see if a system was systemd by looking for the systemd cgroup hierarchy name in any of the victim process's cgroups. This was reliable back in the days of cgroups v1, but alas in v2 where systemd runs all the cgroups if it runs any and there are no longer multiple hierarchies, systemd no longer names its cgroups this way and the test fails, causing us to fall back to the unreliable pre-systemd approach. Use a more reliable approach to detect systemd, the same approach used by sd_booted() in libsystemd; check for the existence of the /run/systemd/system directory. Fix slice detection to work in the absence of a systemd hierarchy name, and everything else works unchanged. Signed-off-by: Nick Alcock --- libproc/Pcontrol.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/libproc/Pcontrol.c b/libproc/Pcontrol.c index 7d9b5055f8201..02da472553d99 100644 --- a/libproc/Pcontrol.c +++ b/libproc/Pcontrol.c @@ -2927,10 +2927,24 @@ Psystem_daemon(pid_t pid, uid_t useruid, const char *sysslice) int fd; /* - * If this is a system running systemd, or we don't know yet, dig out - * the systemd cgroup line from /proc/$pid/cgroup. + * If we don't know if this systemd is running systemd, find out. */ - if (systemd_system != 0) { + if (systemd_system < 0) { + struct stat st; + + if (stat("/run/systemd/system", &st) < 0 || + !S_ISDIR(st.st_mode)) + systemd_system = 0; + else + systemd_system = 1; + _dprintf("systemd system.\n"); + } + + /* + * If this is a system running systemd, dig out the systemd cgroup line + * from /proc/$pid/cgroup. + */ + if (systemd_system) { snprintf(procname, sizeof(procname), "%s/%d/cgroup", procfs_path, pid); @@ -2941,20 +2955,19 @@ Psystem_daemon(pid_t pid, uid_t useruid, const char *sysslice) } while (getline(&buf, &n, fp) >= 0) { - if (strstr(buf, ":name=systemd:") != NULL) { - systemd_system = 1; + if (strstr(buf, ".slice/") != NULL) { break; } } fclose(fp); if (systemd_system < 0) systemd_system = 0; - } - /* - * We have the systemd cgroup line in buf. Look at our slice name. - */ - if (systemd_system) { + /* + * We have our slice's cgroup line in buf. Extract the slice + * name, skipping over the hierarchy number and controller + * fields. + */ char *colon = strchr(buf, ':'); if (colon) colon = strchr(colon + 1, ':'); base-commit: aa63660a7cfcdeb1daf4fb63f1c15f75a1693064 prerequisite-patch-id: fb67028e06b7f26c5cab857477a44609f50a1706 prerequisite-patch-id: f663cbb68f1b30be83e8327ff098fff812ba85e6 prerequisite-patch-id: 7f3cf0adb87fb636276334b0002338ec656f86f7 prerequisite-patch-id: f4716e3bf14ed8233d49d2f7f07bda796f2f2ba7 prerequisite-patch-id: 66c5402691e142580c92584b2eaa4e793146b1a1 prerequisite-patch-id: f96954068cbbaca32084ca999daa825d6668ddd4 prerequisite-patch-id: 6e71861d033f5658a807814dce1161465cc600c5 prerequisite-patch-id: 7e219f03f4634783ebd0550542fa8dbe33e70fa3 prerequisite-patch-id: e7dad794aa72e6d48edc277370f8cca25292d3ba prerequisite-patch-id: 9288cd08c77af53d45e9eef5828bca8bddd22258 prerequisite-patch-id: 994fc434d3e5684814f090acd558aa1d29e737b6 prerequisite-patch-id: 0b84e67ab3948f9edcf987ddbf9ce38df5656ed3 prerequisite-patch-id: cb433110beec8b9e5745acb05930c06b890f4788 prerequisite-patch-id: 71925afd1991d6b1800e0767e5c1420f5b8b43ed prerequisite-patch-id: 67fc0d710b58d6205a6877c4e89b531147b61b51 prerequisite-patch-id: 5b2284dbf7638adacab912d64ccfa775a00632be -- 2.48.1.283.g18c60a128c From sam at gentoo.org Fri Jun 13 20:12:17 2025 From: sam at gentoo.org (Sam James) Date: Fri, 13 Jun 2025 21:12:17 +0100 Subject: [DTrace-devel] [PATCH] Revert "dt_pid: pid grabs should be shortlived" In-Reply-To: <87wm9fd8km.fsf@esperi.org.uk> References: <20250522181016.27661-1-eugene.loh@oracle.com> <87wm9fd8km.fsf@esperi.org.uk> Message-ID: <87cyb7jt9a.fsf@gentoo.org> Nick Alcock via DTrace-devel writes: > On 22 May 2025, eugene loh verbalised: > >> From: Eugene Loh >> >> Commit 4aec5c9931eb ("dt_pid: pid grabs should be shortlived") made >> grabs short-lived. No test cases show the utility of this patch. >> Meanwhile, the patch causes roughly a dozen tests to fail on OL9 >> when the test suite is started remotely using ssh, closing ttys. The > > I think this is a consequence of another bug (Psystem_daemon() was > failing to detect that systemd was running correctly on systemd v2 (Do you mean cgroup v2?) > systems, and we were falling back to the old approach, which is indeed > going to conclude that processes in system groups without controlling > terminals or associated TTYs are system daemons). > > I have a fix for this detection failure under test now and will post it > shortly. From sam at gentoo.org Sat Jun 14 22:04:33 2025 From: sam at gentoo.org (Sam James) Date: Sat, 14 Jun 2025 23:04:33 +0100 Subject: [DTrace-devel] [PATCH] Revert "dt_pid: pid grabs should be shortlived" In-Reply-To: <87cyb7jt9a.fsf@gentoo.org> References: <20250522181016.27661-1-eugene.loh@oracle.com> <87wm9fd8km.fsf@esperi.org.uk> <87cyb7jt9a.fsf@gentoo.org> Message-ID: <8734c2hte6.fsf@gentoo.org> Sam James via DTrace-devel writes: > Nick Alcock via DTrace-devel writes: > >> On 22 May 2025, eugene loh verbalised: >> >>> From: Eugene Loh >>> >>> Commit 4aec5c9931eb ("dt_pid: pid grabs should be shortlived") made >>> grabs short-lived. No test cases show the utility of this patch. >>> Meanwhile, the patch causes roughly a dozen tests to fail on OL9 >>> when the test suite is started remotely using ssh, closing ttys. The >> >> I think this is a consequence of another bug (Psystem_daemon() was >> failing to detect that systemd was running correctly on systemd v2 > > (Do you mean cgroup v2?) Nevermind, I see that in the patch you posted. > >> systems, and we were falling back to the old approach, which is indeed >> going to conclude that processes in system groups without controlling >> terminals or associated TTYs are system daemons). >> >> I have a fix for this detection failure under test now and will post it >> shortly. > > _______________________________________________ > DTrace-devel mailing list > DTrace-devel at oss.oracle.com > https://oss.oracle.com/mailman/listinfo/dtrace-devel From eugene.loh at oracle.com Sun Jun 15 17:50:02 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Sun, 15 Jun 2025 13:50:02 -0400 Subject: [DTrace-devel] [PATCH 11/14] Test: caller and stackdepth tests for proc provider In-Reply-To: <87ikkzbsmb.fsf@esperi.org.uk> References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-11-eugene.loh@oracle.com> <87ikkzbsmb.fsf@esperi.org.uk> Message-ID: <4e0a07a6-04a0-3d60-af59-ba32a41a03f6@oracle.com> Thanks. I'm getting to these out of order, but I figured I'd mention that I'm going to turn the capitalized "Test:" into "test:" for this series of patches to conform to the style in related patches. On 6/13/25 10:53, Nick Alcock wrote: > On 22 May 2025, eugene loh told this: > >> From: Eugene Loh >> >> Signed-off-by: Eugene Loh > Reviewed-by: Nick Alcock > From eugene.loh at oracle.com Mon Jun 16 19:21:09 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Mon, 16 Jun 2025 15:21:09 -0400 Subject: [DTrace-devel] [PATCH 01/14] Fix stack-skip counts for caller and stackdepth In-Reply-To: <87sek3d83m.fsf@esperi.org.uk> References: <20250522180118.27343-1-eugene.loh@oracle.com> <87sek3d83m.fsf@esperi.org.uk> Message-ID: <6cdb7118-e678-57e7-adff-a74a1ff39e19@oracle.com> On 6/13/25 10:33, Nick Alcock wrote: > On 22 May 2025, eugene loh told this: > >> From: Eugene Loh >> >> Apparently, when we call the BPF get_stack() helper function, >> it generally knows how many frames to skip to get the real kernel >> stack. For fentry/fexit, however, this is apparently not the case, >> and commit bc65cb44d >> ("cg: allow providers to specify a skip count for stack retrieval") >> added the ability to skip frames for fentry/fexit probes. >> >> When this "skip" is needed, however, it must must be even deeper >> when we descend further frames, such as when we call dt_bpf_*() >> precompiled functions. > Ack. > >> Add this support for dt_bpf_caller() and dt_bpf_stackdepth(). >> That is, if there are stack-skip frames, skip yet one more frame >> when inside a bpf/get_bvar.c function. > The general approach here seems sound, but this confuses me. Is the > assumption that if the skip is not needed, get_stack() will itself know > how many frames to skip, and will skip dt_dt_bvar_caller() for you? Yes.? I confirmed this with tests. > (So a zero skip is actually a "the system knows", and a nonzero skip > causes the system to not skip anything, so you have to do all the > skipping yourself? Yes. > This behaviour is not documented in bpf_get_stack()'s documentation, > which absolutely does not mean it doesn't do it...) Yup:? I did not learn this from documentation! >> Note that we declare the skip count volatile. The compiler might >> optimize code that uses the STACK_SKIP value, but we will subsequently >> perform relocations that adjust this value. > ... why doesn't this apply to every other extern global variable in > get_bvar()? They're all similarly relocated... Right.? There is potentially a broader problem.? But we simply do not have evidence of misbehavior in other cases.? Ruggedizing other cases could be the subject of a different patch. The problem in this case is that the compiler seems to assume &symbol!=0, which is reasonable except that we violate that behavior for our relocation tricks. Consider the C code: ??? 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; ??????? volatile uint64_t skip = (uint64_t)(&STACK_SKIP); ??????? retv = bpf_get_stack(dctx->ctx, ???????????????????????????? buf, ???????????????????????????? bufsiz, ???????????????????????????? skip & BPF_F_SKIP_FIELD_MASK); ??????? if (skip) ??????????????? return retv / sizeof(uint64_t) - 1;????? // branch "A" ??????? return retv / sizeof(uint64_t);????????????????? // branch "B" ??? } If you omit "volatile", the compiler assumes &STACK_SKIP!=0. The emitted code has: ??? *)? no run-time "if (skip)" check ??? *)? no code for branch "B" ??? *)? only code for branch "A" If you include "volatile", however, the compiler caches &STACK_SKIP on the BPF stack and later performs a run-time check on its value to correctly execute either branch "A" or branch "B". Incidentally, I looked at this using the function like this: ??? profile:::tick-1s, ??? fbt:vmlinux:ksys_write:entry ??? { ?????? trace(stackdepth); ??? } Notice that the profile probe has STACK_SKIP==0 while the fbt probe has STACK_SKIP==4. I looked at the disassembly in three ways: ??? *)? as emitted by the compiler:? objdump -d build/bpf--get_bvar.o ?????? (not too interesting but establishes a baseline;? e.g., that a branch is missing) ??? *)? after relocation for tick-1s (-xdisasm=8 -S) ??? *)? after relocation for fbt::ksys_write:entry (-xdisasm=8 -S) The latter two confirm the relocations are correct. >> Signed-off-by: Eugene Loh >> --- >> bpf/get_bvar.c | 17 ++++++++++++++--- >> 1 file changed, 14 insertions(+), 3 deletions(-) >> >> diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c >> index 9625e764e..99a6503d5 100644 >> --- a/bpf/get_bvar.c >> +++ b/bpf/get_bvar.c >> @@ -53,12 +53,17 @@ noinline uint64_t dt_bvar_args(const dt_dctx_t *dctx, uint32_t idx) >> >> noinline uint64_t dt_bvar_caller(const dt_dctx_t *dctx) >> { >> - uint64_t buf[2] = { 0, }; >> + uint64_t buf[3] = { 0, }; >> + volatile uint64_t >> + skip = (uint64_t)(&STACK_SKIP); >> >> if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), >> - (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK) < 0) >> + skip & BPF_F_SKIP_FIELD_MASK) < 0) >> return 0; >> >> + /* If we had to skip any frames, account for the dt_bvar_caller() frame. */ >> + if (skip) >> + return buf[2]; >> return buf[1]; >> } >> >> @@ -203,9 +208,11 @@ 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; >> + volatile uint64_t >> + skip = (uint64_t)(&STACK_SKIP); >> >> retv = bpf_get_stack(dctx->ctx, buf, bufsiz, >> - (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK); >> + skip & BPF_F_SKIP_FIELD_MASK); >> if (retv < 0) >> return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); >> >> @@ -217,7 +224,11 @@ noinline uint64_t dt_bvar_stackdepth(const dt_dctx_t *dctx) >> * 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. >> + * >> + * If we had to skip any frames, account for the dt_bvar_stackdepth() frame. >> */ >> + if (skip) >> + return retv / sizeof(uint64_t) - 1; >> return retv / sizeof(uint64_t); >> } From kris.van.hees at oracle.com Wed Jun 18 19:41:09 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Wed, 18 Jun 2025 15:41:09 -0400 Subject: [DTrace-devel] [PATCH] libproc: make Psystem_daemon() detect modern systemd properly In-Reply-To: <20250613164637.3110-1-nick.alcock@oracle.com> References: <20250613164637.3110-1-nick.alcock@oracle.com> Message-ID: On Fri, Jun 13, 2025 at 05:46:37PM +0100, Nick Alcock wrote: > Psystem_daemon() is used when carrying out shortlived grabs to detect > whether a process is too risky to carry out invasive grabs of (you wouldn't > usually want to stop syslogd or, God forbid, try to ptrace PID 1, unless > explicitly requested via -p: the process just coming up in routine probe > firing is not enough). > > This has two code paths: a reliable one for systemd systems (which checks to > see if the process is in the system slice, which contains precisely and only > system daemons), and an unreliable one for other systems (which does the old > Unix approach of consdering anything in the user uid range or with a TTY or > with open standard FDs to TTYs to be not system daemons, and everything else > to possibly be one). > > We were checking to see if a system was systemd by looking for the systemd > cgroup hierarchy name in any of the victim process's cgroups. This was > reliable back in the days of cgroups v1, but alas in v2 where systemd runs > all the cgroups if it runs any and there are no longer multiple hierarchies, > systemd no longer names its cgroups this way and the test fails, causing us > to fall back to the unreliable pre-systemd approach. > > Use a more reliable approach to detect systemd, the same approach used by > sd_booted() in libsystemd; check for the existence of the > /run/systemd/system directory. Fix slice detection to work in the absence > of a systemd hierarchy name, and everything else works unchanged. Is /run/systems/system guaranteed to always be the correct path or is that configurable in systemd and thus could change depending on distro etc? > > Signed-off-by: Nick Alcock > --- > libproc/Pcontrol.c | 33 +++++++++++++++++++++++---------- > 1 file changed, 23 insertions(+), 10 deletions(-) > > diff --git a/libproc/Pcontrol.c b/libproc/Pcontrol.c > index 7d9b5055f8201..02da472553d99 100644 > --- a/libproc/Pcontrol.c > +++ b/libproc/Pcontrol.c > @@ -2927,10 +2927,24 @@ Psystem_daemon(pid_t pid, uid_t useruid, const char *sysslice) > int fd; > > /* > - * If this is a system running systemd, or we don't know yet, dig out > - * the systemd cgroup line from /proc/$pid/cgroup. > + * If we don't know if this systemd is running systemd, find out. > */ > - if (systemd_system != 0) { > + if (systemd_system < 0) { > + struct stat st; > + > + if (stat("/run/systemd/system", &st) < 0 || > + !S_ISDIR(st.st_mode)) > + systemd_system = 0; > + else > + systemd_system = 1; > + _dprintf("systemd system.\n"); > + } > + > + /* > + * If this is a system running systemd, dig out the systemd cgroup line > + * from /proc/$pid/cgroup. > + */ > + if (systemd_system) { > snprintf(procname, sizeof(procname), "%s/%d/cgroup", > procfs_path, pid); > > @@ -2941,20 +2955,19 @@ Psystem_daemon(pid_t pid, uid_t useruid, const char *sysslice) > } > > while (getline(&buf, &n, fp) >= 0) { > - if (strstr(buf, ":name=systemd:") != NULL) { > - systemd_system = 1; > + if (strstr(buf, ".slice/") != NULL) { > break; > } > } > fclose(fp); > if (systemd_system < 0) > systemd_system = 0; > - } > > - /* > - * We have the systemd cgroup line in buf. Look at our slice name. > - */ > - if (systemd_system) { > + /* > + * We have our slice's cgroup line in buf. Extract the slice > + * name, skipping over the hierarchy number and controller > + * fields. > + */ > char *colon = strchr(buf, ':'); > if (colon) > colon = strchr(colon + 1, ':'); > > base-commit: aa63660a7cfcdeb1daf4fb63f1c15f75a1693064 > prerequisite-patch-id: fb67028e06b7f26c5cab857477a44609f50a1706 > prerequisite-patch-id: f663cbb68f1b30be83e8327ff098fff812ba85e6 > prerequisite-patch-id: 7f3cf0adb87fb636276334b0002338ec656f86f7 > prerequisite-patch-id: f4716e3bf14ed8233d49d2f7f07bda796f2f2ba7 > prerequisite-patch-id: 66c5402691e142580c92584b2eaa4e793146b1a1 > prerequisite-patch-id: f96954068cbbaca32084ca999daa825d6668ddd4 > prerequisite-patch-id: 6e71861d033f5658a807814dce1161465cc600c5 > prerequisite-patch-id: 7e219f03f4634783ebd0550542fa8dbe33e70fa3 > prerequisite-patch-id: e7dad794aa72e6d48edc277370f8cca25292d3ba > prerequisite-patch-id: 9288cd08c77af53d45e9eef5828bca8bddd22258 > prerequisite-patch-id: 994fc434d3e5684814f090acd558aa1d29e737b6 > prerequisite-patch-id: 0b84e67ab3948f9edcf987ddbf9ce38df5656ed3 > prerequisite-patch-id: cb433110beec8b9e5745acb05930c06b890f4788 > prerequisite-patch-id: 71925afd1991d6b1800e0767e5c1420f5b8b43ed > prerequisite-patch-id: 67fc0d710b58d6205a6877c4e89b531147b61b51 > prerequisite-patch-id: 5b2284dbf7638adacab912d64ccfa775a00632be > -- > 2.48.1.283.g18c60a128c > From kris.van.hees at oracle.com Thu Jun 19 03:59:42 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Wed, 18 Jun 2025 23:59:42 -0400 Subject: [DTrace-devel] [PATCH] usdt parser: fix memory leak in provider and probe htabs Message-ID: The prvmap and prbmap hashtable implementation was lacking code to ensure that entries are freed when the hashtables are destroyed. In addition, the pvp->pmap hashtables were also not cleaned up. To provide cleaner data structures and to facilitate cleanup, tracepoint probes are now always removed from prbmap and either added to the pvp->pmap hashtable or added to the list of tracepoints for a particular probe. Therefore, when the prbmap is destroyed it no longer contains any entries. So, only pvp->pmap hashtables can contain probes. If they are function specific, they represent a tracepoint (and may have additional tracepoints linked to them). If they are not function specific, they provide a probe definition and they will contain probe argument data that needs freeing. Signed-off-by: Kris Van Hees --- libcommon/usdt_parser_notes.c | 82 +++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/libcommon/usdt_parser_notes.c b/libcommon/usdt_parser_notes.c index cdadf4b2..c6fc3476 100644 --- a/libcommon/usdt_parser_notes.c +++ b/libcommon/usdt_parser_notes.c @@ -161,7 +161,25 @@ static int prv_cmp(const dt_provider_t *p, const dt_provider_t *q) { } DEFINE_HE_STD_LINK_FUNCS(prv, dt_provider_t, he) -DEFINE_HTAB_STD_OPS(prv) + +static void * +prv_del_prov(dt_provider_t *head, dt_provider_t *pvp) +{ + head = prv_del(head, pvp); + + dt_htab_destroy(pvp->pmap); + free(pvp); + + return head; +} + +static dt_htab_ops_t prv_htab_ops = { + .hval = (htab_hval_fn)prv_hval, + .cmp = (htab_cmp_fn)prv_cmp, + .add = (htab_add_fn)prv_add, + .del = (htab_del_fn)prv_del_prov, + .next = (htab_next_fn)prv_next +}; static uint32_t prb_hval(const dt_probe_t *prp) { uint32_t hval; @@ -205,6 +223,41 @@ static int prb_cmp(const dt_probe_t *p, const dt_probe_t *q) { DEFINE_HE_STD_LINK_FUNCS(prb, dt_probe_t, he) DEFINE_HTAB_STD_OPS(prb) +static void * +prb_del_probe(dt_probe_t *head, dt_probe_t *prp) +{ + head = prb_del(head, prp); + + /* + * If this is not a function-specific probe (from a prov note), free + * the translated arg data and the probe itself. + * If this is a function-specific probe (from a usdt note), walk the + * list of tracepoint probe, freeing each probe in the list. + */ + if (prp->fun == NULL) { + free(prp->xargs); + free(prp->xmap); + free(prp); + } else { + dt_probe_t *nxt; + + do { + nxt = prp->next; + free(prp); + } while ((prp = nxt) != NULL); + } + + return head; +} + +static dt_htab_ops_t pmap_htab_ops = { + .hval = (htab_hval_fn)prb_hval, + .cmp = (htab_cmp_fn)prb_cmp, + .add = (htab_add_fn)prb_add, + .del = (htab_del_fn)prb_del_probe, + .next = (htab_next_fn)prb_next +}; + /* * Return the cummulative string length of 'cnt' consecutive 0-terminated * strings. If skip > 0, it indicates how many extra bytes are to be skipped @@ -252,7 +305,7 @@ parse_prov_note(int out, dof_helper_t *dhp, usdt_data_t *data, memset(pvp, 0, sizeof(dt_provider_t)); pvp->name = prvt.name; dt_htab_insert(prvmap, pvp); - pvp->pmap = dt_htab_create(&prb_htab_ops); + pvp->pmap = dt_htab_create(&pmap_htab_ops); } else { usdt_error(out, EEXIST, "Duplicate provider: %s", prvt.name); return -1; @@ -715,30 +768,24 @@ usdt_parse_notes(int out, dof_helper_t *dhp, usdt_data_t *data) * tracepoint probe to the provider. * In either cases, argument data is copied. */ + dt_htab_delete(prbmap, ptp); if (prp->fun != NULL) { ptp->next = prp->next; - ptp->nargc = prp->nargc; - ptp->nargs = prp->nargs; - ptp->nargsz = prp->nargsz; - ptp->xargc = prp->xargc; - ptp->xargs = prp->xargs; - ptp->xargsz = prp->xargsz; - ptp->xmap = prp->xmap; prp->next = ptp; prp->ntp++; } else { - dt_htab_delete(prbmap, ptp); dt_htab_insert(pvp->pmap, ptp); ptp->ntp = 1; - ptp->nargc = prp->nargc; - ptp->nargs = prp->nargs; - ptp->nargsz = prp->nargsz; - ptp->xargc = prp->xargc; - ptp->xargs = prp->xargs; - ptp->xargsz = prp->xargsz; - ptp->xmap = prp->xmap; pvp->probec++; } + + ptp->nargc = prp->nargc; + ptp->nargs = prp->nargs; + ptp->nargsz = prp->nargsz; + ptp->xargc = prp->xargc; + ptp->xargs = prp->xargs; + ptp->xargsz = prp->xargsz; + ptp->xmap = prp->xmap; } /* Emit any provider that has tracepoints. */ @@ -754,6 +801,7 @@ err: rc = -1; out: + assert(dt_htab_entries(prbmap) == 0); dt_htab_destroy(prvmap); dt_htab_destroy(prbmap); -- 2.43.5 From nick.alcock at oracle.com Thu Jun 19 11:58:21 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Thu, 19 Jun 2025 12:58:21 +0100 Subject: [DTrace-devel] [PATCH] usdt parser: fix memory leak in provider and probe htabs In-Reply-To: (Kris Van Hees's message of "Wed, 18 Jun 2025 23:59:42 -0400") References: Message-ID: <8734bw0wpu.fsf@esperi.org.uk> On 19 Jun 2025, Kris Van Hees spake thusly: > The prvmap and prbmap hashtable implementation was lacking code to > ensure that entries are freed when the hashtables are destroyed. In > addition, the pvp->pmap hashtables were also not cleaned up. Much the same as what I wrote yesterday, but simpler and more obviously correct, so I'd say pull it in, and I'll rebase my jailing series on top of it. > To provide cleaner data structures and to facilitate cleanup, tracepoint > probes are now always removed from prbmap and either added to the > pvp->pmap hashtable or added to the list of tracepoints for a particular > probe. Therefore, when the prbmap is destroyed it no longer contains > any entries. Very nice... > So, only pvp->pmap hashtables can contain probes. If they are function > specific, they represent a tracepoint (and may have additional > tracepoints linked to them). If they are not function specific, they > provide a probe definition and they will contain probe argument data > that needs freeing. ... but perhaps these two paragraphs should be in a comment in the code? The shape of the data structures does matter to maintenance, after all. > Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock , particularly if you make those two paras comments. -- NULL && (void) From nick.alcock at oracle.com Thu Jun 19 12:00:08 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Thu, 19 Jun 2025 13:00:08 +0100 Subject: [DTrace-devel] [PATCH] libproc: make Psystem_daemon() detect modern systemd properly In-Reply-To: (Kris Van Hees's message of "Wed, 18 Jun 2025 15:41:09 -0400") References: <20250613164637.3110-1-nick.alcock@oracle.com> Message-ID: <87y0toym9j.fsf@esperi.org.uk> On 18 Jun 2025, Kris Van Hees verbalised: > On Fri, Jun 13, 2025 at 05:46:37PM +0100, Nick Alcock wrote: >> Psystem_daemon() is used when carrying out shortlived grabs to detect >> whether a process is too risky to carry out invasive grabs of (you wouldn't >> usually want to stop syslogd or, God forbid, try to ptrace PID 1, unless >> explicitly requested via -p: the process just coming up in routine probe >> firing is not enough). >> >> This has two code paths: a reliable one for systemd systems (which checks to >> see if the process is in the system slice, which contains precisely and only >> system daemons), and an unreliable one for other systems (which does the old >> Unix approach of consdering anything in the user uid range or with a TTY or >> with open standard FDs to TTYs to be not system daemons, and everything else >> to possibly be one). >> >> We were checking to see if a system was systemd by looking for the systemd >> cgroup hierarchy name in any of the victim process's cgroups. This was >> reliable back in the days of cgroups v1, but alas in v2 where systemd runs >> all the cgroups if it runs any and there are no longer multiple hierarchies, >> systemd no longer names its cgroups this way and the test fails, causing us >> to fall back to the unreliable pre-systemd approach. >> >> Use a more reliable approach to detect systemd, the same approach used by >> sd_booted() in libsystemd; check for the existence of the >> /run/systemd/system directory. Fix slice detection to work in the absence >> of a systemd hierarchy name, and everything else works unchanged. > > Is /run/systems/system guaranteed to always be the correct path or is that > configurable in systemd and thus could change depending on distro etc? It's not configurable. I got the path from the manpage for sd_booted(3), which also recommends just doing the check yourself directly :) so as canonized as anything like this can be, much more so than the guesswork we were doing before. From nick.alcock at oracle.com Thu Jun 19 12:51:29 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Thu, 19 Jun 2025 13:51:29 +0100 Subject: [DTrace-devel] [PATCH] Revert "dt_pid: pid grabs should be shortlived" In-Reply-To: <8734c2hte6.fsf@gentoo.org> (Sam James's message of "Sat, 14 Jun 2025 23:04:33 +0100") References: <20250522181016.27661-1-eugene.loh@oracle.com> <87wm9fd8km.fsf@esperi.org.uk> <87cyb7jt9a.fsf@gentoo.org> <8734c2hte6.fsf@gentoo.org> Message-ID: <87tt4bzyge.fsf@esperi.org.uk> On 14 Jun 2025, Sam James outgrape: > Sam James via DTrace-devel writes: > >> Nick Alcock via DTrace-devel writes: >> >>> On 22 May 2025, eugene loh verbalised: >>> >>>> From: Eugene Loh >>>> >>>> Commit 4aec5c9931eb ("dt_pid: pid grabs should be shortlived") made >>>> grabs short-lived. No test cases show the utility of this patch. >>>> Meanwhile, the patch causes roughly a dozen tests to fail on OL9 >>>> when the test suite is started remotely using ssh, closing ttys. The >>> >>> I think this is a consequence of another bug (Psystem_daemon() was >>> failing to detect that systemd was running correctly on systemd v2 >> >> (Do you mean cgroup v2?) Yes indeed. The heat and pollen is ruining my brain :/ $random_related_word v2 From nick.alcock at oracle.com Thu Jun 19 12:52:40 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Thu, 19 Jun 2025 13:52:40 +0100 Subject: [DTrace-devel] [PATCH 11/14] Test: caller and stackdepth tests for proc provider In-Reply-To: <4e0a07a6-04a0-3d60-af59-ba32a41a03f6@oracle.com> (Eugene Loh's message of "Sun, 15 Jun 2025 13:50:02 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-11-eugene.loh@oracle.com> <87ikkzbsmb.fsf@esperi.org.uk> <4e0a07a6-04a0-3d60-af59-ba32a41a03f6@oracle.com> Message-ID: <87plezzyef.fsf@esperi.org.uk> On 15 Jun 2025, Eugene Loh stated: > Thanks. > > I'm getting to these out of order, but I figured I'd mention that I'm going to turn the capitalized "Test:" into "test:" for this > series of patches to conform to the style in related patches. Makes sense! I totally failed to notice that. From nick.alcock at oracle.com Thu Jun 19 13:03:56 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Thu, 19 Jun 2025 14:03:56 +0100 Subject: [DTrace-devel] [PATCH 01/14] Fix stack-skip counts for caller and stackdepth In-Reply-To: <6cdb7118-e678-57e7-adff-a74a1ff39e19@oracle.com> (Eugene Loh's message of "Mon, 16 Jun 2025 15:21:09 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <87sek3d83m.fsf@esperi.org.uk> <6cdb7118-e678-57e7-adff-a74a1ff39e19@oracle.com> Message-ID: <87jz57zxvn.fsf@esperi.org.uk> On 16 Jun 2025, Eugene Loh verbalised: > On 6/13/25 10:33, Nick Alcock wrote: > >>> Note that we declare the skip count volatile. The compiler might >>> optimize code that uses the STACK_SKIP value, but we will subsequently >>> perform relocations that adjust this value. >> ... why doesn't this apply to every other extern global variable in >> get_bvar()? They're all similarly relocated... > > Right.? There is potentially a broader problem.? But we simply do not have evidence of misbehavior in other cases.? Ruggedizing > other cases could be the subject of a different patch. Aha, OK. I was just wondering if there was some extra reason. > The problem in this case is that the compiler seems to assume &symbol!=0, which is reasonable except that we violate that behavior > for our relocation tricks. I wonder where the code for that is... plenty of symbols have value zero. But, really... > Consider the C code: > > ??? 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); Hm... extern uint64_t STACK_SKIP; So we encode information about the stack size and skip value by encoding it in the *address* of the variable? Is there some reason we don't use its value? unlike the stack offset, we're *using* it as a value, not an address... > ??????? uint64_t????????? retv; > ??????? volatile uint64_t skip = (uint64_t)(&STACK_SKIP); > > ??????? retv = bpf_get_stack(dctx->ctx, > ???????????????????????????? buf, > ???????????????????????????? bufsiz, > ???????????????????????????? skip & BPF_F_SKIP_FIELD_MASK); > > ??????? if (skip) > ??????????????? return retv / sizeof(uint64_t) - 1;????? // branch "A" > ??????? return retv / sizeof(uint64_t);????????????????? // branch "B" > ??? } > > If you omit "volatile", the compiler assumes &STACK_SKIP!=0. The emitted code has: (which is a reasonable assumption if not freestanding, I'd say. Why don't we compile BPF code with -ffreestanding? BPF is almost the *definition* of a freestanding environment...) > ??? *)? no run-time "if (skip)" check > > ??? *)? no code for branch "B" > > ??? *)? only code for branch "A" > > If you include "volatile", however, the compiler caches &STACK_SKIP on > the BPF stack and later performs a run-time check on its value to > correctly execute either branch "A" or branch "B". This feels very mucvh like a workaround to me. Does compiling BPF with -ffreestanding help? I mean it fixes a bug, so I suppose it should go in if nothing else works, but using volatile is almost always a desperate sticking plaster and this feels like one of those occasions to me. -- NULL && (void) From noreply at github.com Thu Jun 19 15:39:04 2025 From: noreply at github.com (Kris Van Hees) Date: Thu, 19 Jun 2025 08:39:04 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] 23cdaf: usdt parser: fix memory leak in provider and probe... Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: 23cdaf54ce759b69d8db612d59e5f9bfebcb70bb https://github.com/oracle/dtrace-utils/commit/23cdaf54ce759b69d8db612d59e5f9bfebcb70bb Author: Kris Van Hees Date: 2025-06-19 (Thu, 19 Jun 2025) Changed paths: M libcommon/usdt_parser_notes.c Log Message: ----------- usdt parser: fix memory leak in provider and probe htabs The prvmap and prbmap hashtable implementation was lacking code to ensure that entries are freed when the hashtables are destroyed. In addition, the pvp->pmap hashtables were also not cleaned up. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock To unsubscribe from these emails, change your notification settings at https://github.com/oracle/dtrace-utils/settings/notifications From noreply at github.com Thu Jun 19 15:42:19 2025 From: noreply at github.com (Kris Van Hees) Date: Thu, 19 Jun 2025 08:42:19 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] Message-ID: Branch: refs/heads/kvh/usdt-dev 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 Thu Jun 19 16:20:22 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 19 Jun 2025 12:20:22 -0400 Subject: [DTrace-devel] [PATCH 01/14] Fix stack-skip counts for caller and stackdepth In-Reply-To: <87jz57zxvn.fsf@esperi.org.uk> References: <20250522180118.27343-1-eugene.loh@oracle.com> <87sek3d83m.fsf@esperi.org.uk> <6cdb7118-e678-57e7-adff-a74a1ff39e19@oracle.com> <87jz57zxvn.fsf@esperi.org.uk> Message-ID: On Thu, Jun 19, 2025 at 02:03:56PM +0100, Nick Alcock wrote: > On 16 Jun 2025, Eugene Loh verbalised: > > > On 6/13/25 10:33, Nick Alcock wrote: > > > >>> Note that we declare the skip count volatile. The compiler might > >>> optimize code that uses the STACK_SKIP value, but we will subsequently > >>> perform relocations that adjust this value. > >> ... why doesn't this apply to every other extern global variable in > >> get_bvar()? They're all similarly relocated... > > > > Right.? There is potentially a broader problem.? But we simply do not have evidence of misbehavior in other cases.? Ruggedizing > > other cases could be the subject of a different patch. > > Aha, OK. I was just wondering if there was some extra reason. > > > The problem in this case is that the compiler seems to assume &symbol!=0, which is reasonable except that we violate that behavior > > for our relocation tricks. > > I wonder where the code for that is... plenty of symbols have value > zero. > > But, really... > > > Consider the C code: > > > > ??? 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); > > Hm... > > extern uint64_t STACK_SKIP; > > So we encode information about the stack size and skip value by encoding > it in the *address* of the variable? Is there some reason we don't use > its value? unlike the stack offset, we're *using* it as a value, not an > address... The issue seems to be (and perhaps this is a cross compiler problem) that e.g. extern uint64_t PC; and then code accessing the value of PC (e.g. foo(PC) as a call argument) will yield: 50: 18 02 00 00 00 00 00 00 lddw %r2,0 58: 00 00 00 00 00 00 00 00 50: R_BPF_INSN_64 PC 60: 79 22 00 00 00 00 00 00 ldxdw %r2,[%r2+0] which shows that it is interpreting PC as an address to a symbol, because it loads the address of the symbol and then dereferences it with offset 0. So, we cannot plug in the value during relocation because the only value we can put there would be an address where the vlaue can be found. To get around this, we "use" Tthe address as the entity to store the value in, knowing that we *never* will interpret it as an address for these specific externs. > > ??????? uint64_t????????? retv; > > ??????? volatile uint64_t skip = (uint64_t)(&STACK_SKIP); > > > > ??????? retv = bpf_get_stack(dctx->ctx, > > ???????????????????????????? buf, > > ???????????????????????????? bufsiz, > > ???????????????????????????? skip & BPF_F_SKIP_FIELD_MASK); > > > > ??????? if (skip) > > ??????????????? return retv / sizeof(uint64_t) - 1;????? // branch "A" > > ??????? return retv / sizeof(uint64_t);????????????????? // branch "B" > > ??? } > > > > If you omit "volatile", the compiler assumes &STACK_SKIP!=0. The emitted code has: > > (which is a reasonable assumption if not freestanding, I'd say. Why > don't we compile BPF code with -ffreestanding? BPF is almost the > *definition* of a freestanding environment...) > > > ??? *)? no run-time "if (skip)" check > > > > ??? *)? no code for branch "B" > > > > ??? *)? only code for branch "A" > > > > If you include "volatile", however, the compiler caches &STACK_SKIP on > > the BPF stack and later performs a run-time check on its value to > > correctly execute either branch "A" or branch "B". > > This feels very mucvh like a workaround to me. Does compiling BPF with > -ffreestanding help? > > I mean it fixes a bug, so I suppose it should go in if nothing else > works, but using volatile is almost always a desperate sticking plaster > and this feels like one of those occasions to me. > > -- > NULL && (void) From kris.van.hees at oracle.com Thu Jun 19 16:32:13 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 19 Jun 2025 12:32:13 -0400 Subject: [DTrace-devel] [PATCH 01/14] Fix stack-skip counts for caller and stackdepth In-Reply-To: References: <20250522180118.27343-1-eugene.loh@oracle.com> <87sek3d83m.fsf@esperi.org.uk> <6cdb7118-e678-57e7-adff-a74a1ff39e19@oracle.com> <87jz57zxvn.fsf@esperi.org.uk> Message-ID: On Thu, Jun 19, 2025 at 12:20:22PM -0400, Kris Van Hees wrote: > On Thu, Jun 19, 2025 at 02:03:56PM +0100, Nick Alcock wrote: > > On 16 Jun 2025, Eugene Loh verbalised: > > > > > On 6/13/25 10:33, Nick Alcock wrote: > > > > > >>> Note that we declare the skip count volatile. The compiler might > > >>> optimize code that uses the STACK_SKIP value, but we will subsequently > > >>> perform relocations that adjust this value. > > >> ... why doesn't this apply to every other extern global variable in > > >> get_bvar()? They're all similarly relocated... > > > > > > Right.? There is potentially a broader problem.? But we simply do not have evidence of misbehavior in other cases.? Ruggedizing > > > other cases could be the subject of a different patch. > > > > Aha, OK. I was just wondering if there was some extra reason. > > > > > The problem in this case is that the compiler seems to assume &symbol!=0, which is reasonable except that we violate that behavior > > > for our relocation tricks. > > > > I wonder where the code for that is... plenty of symbols have value > > zero. > > > > But, really... > > > > > Consider the C code: > > > > > > ??? 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); > > > > Hm... > > > > extern uint64_t STACK_SKIP; > > > > So we encode information about the stack size and skip value by encoding > > it in the *address* of the variable? Is there some reason we don't use > > its value? unlike the stack offset, we're *using* it as a value, not an > > address... > > The issue seems to be (and perhaps this is a cross compiler problem) that e.g. > > extern uint64_t PC; > > and then code accessing the value of PC (e.g. foo(PC) as a call argument) will > yield: > > 50: 18 02 00 00 00 00 00 00 lddw %r2,0 > 58: 00 00 00 00 00 00 00 00 > 50: R_BPF_INSN_64 PC > 60: 79 22 00 00 00 00 00 00 ldxdw %r2,[%r2+0] > > which shows that it is interpreting PC as an address to a symbol, because it > loads the address of the symbol and then dereferences it with offset 0. So, > we cannot plug in the value during relocation because the only value we can > put there would be an address where the vlaue can be found. To get around > this, we "use" Tthe address as the entity to store the value in, knowing that > we *never* will interpret it as an address for these specific externs. Not a compiler error - since PC is extern uint64_t PC it *is* a variable and so it is present (and accessible) as an address in .data in the location where it is actually defined. Since we never define it, we don't have a .data (which is fine because we only use this for constants known at link time) BUT the compiler of course is free to assume that we *do* have an address to the storage location for PC and thus that we get the value that way. It does not know that the value is constant. So, the trick I use is needed to make this work. > > > ??????? uint64_t????????? retv; > > > ??????? volatile uint64_t skip = (uint64_t)(&STACK_SKIP); > > > > > > ??????? retv = bpf_get_stack(dctx->ctx, > > > ???????????????????????????? buf, > > > ???????????????????????????? bufsiz, > > > ???????????????????????????? skip & BPF_F_SKIP_FIELD_MASK); > > > > > > ??????? if (skip) > > > ??????????????? return retv / sizeof(uint64_t) - 1;????? // branch "A" > > > ??????? return retv / sizeof(uint64_t);????????????????? // branch "B" > > > ??? } > > > > > > If you omit "volatile", the compiler assumes &STACK_SKIP!=0. The emitted code has: > > > > (which is a reasonable assumption if not freestanding, I'd say. Why > > don't we compile BPF code with -ffreestanding? BPF is almost the > > *definition* of a freestanding environment...) > > > > > ??? *)? no run-time "if (skip)" check > > > > > > ??? *)? no code for branch "B" > > > > > > ??? *)? only code for branch "A" > > > > > > If you include "volatile", however, the compiler caches &STACK_SKIP on > > > the BPF stack and later performs a run-time check on its value to > > > correctly execute either branch "A" or branch "B". > > > > This feels very mucvh like a workaround to me. Does compiling BPF with > > -ffreestanding help? > > > > I mean it fixes a bug, so I suppose it should go in if nothing else > > works, but using volatile is almost always a desperate sticking plaster > > and this feels like one of those occasions to me. > > > > -- > > NULL && (void) From noreply at github.com Fri Jun 20 21:03:58 2025 From: noreply at github.com (Kris Van Hees) Date: Fri, 20 Jun 2025 14:03:58 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] Message-ID: Branch: refs/tags/2.0.3 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 alan.maguire at oracle.com Mon Jun 23 10:13:05 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Mon, 23 Jun 2025 11:13:05 +0100 Subject: [DTrace-devel] [PATCH v4 0/5] add support for stapsdt probes Message-ID: <20250623101310.1649756-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 prepares for this support by adding counting to parsing of stapsdt probe args (since they do not include an explicit arg count); Patch 2 adds the support, while patches 3-5 add tests covering that support. Changes since v3: - merged with USDT ELF note changes; since these use the same argument-parsing/access code, no need to add code for this now (patch 2) - updated said ELF note parsing to count as well as parse arguments since stapsdt probes do not provide an arg count (patch 1) - added explicit stapsdt provider to reflect that stapsdt probes are fundamentally different and do not auto-register for discovery via ioctl (patch 2, Kris) - added simple pid wildcarding support for /proc map parsing. Changes since v2: - updated terminology to distinguish stapsdt from USDT probes Alan Maguire (5): usdt: have copy_args() count args while parsing them 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 | 1 + libdtrace/dt_pid.c | 288 +++++++++++ libdtrace/dt_prov_uprobe.c | 54 +- 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 +++++ 10 files changed, 1184 insertions(+), 9 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 Mon Jun 23 10:13:06 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Mon, 23 Jun 2025 11:13:06 +0100 Subject: [DTrace-devel] [PATCH v4 1/5] usdt: have copy_args() count args while parsing them In-Reply-To: <20250623101310.1649756-1-alan.maguire@oracle.com> References: <20250623101310.1649756-1-alan.maguire@oracle.com> Message-ID: <20250623101310.1649756-2-alan.maguire@oracle.com> stapsdt probes do not include an argument count, so the only way to count them is to parse the parameter string. Adjust copy_args() to set upp->sargc while parsing upp->sargv. Signed-off-by: Alan Maguire --- libdtrace/dt_prov_uprobe.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index cf5cfd43..2cbd8910 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -1145,9 +1145,9 @@ static void enable_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp) } /* - * Generate code that populates the probe arguments. + * Generate code that populates, counts the probe arguments. */ -static void copy_args(dt_pcb_t *pcb, const dt_uprobe_t *upp) +static void copy_args(dt_pcb_t *pcb, dt_uprobe_t *upp) { dtrace_hdl_t *dtp = pcb->pcb_hdl; dt_irlist_t *dlp = &pcb->pcb_ir; @@ -1158,7 +1158,7 @@ static void copy_args(dt_pcb_t *pcb, const dt_uprobe_t *upp) assert(pvp != NULL); - for (i = 0; i < upp->sargc; i++) { + for (i = 0; strlen(p) > 0; i++) { int ssize, disp, len; char *reg = NULL; int64_t val = 0; @@ -1425,6 +1425,7 @@ static void copy_args(dt_pcb_t *pcb, const dt_uprobe_t *upp) usdt_error(pcb, "Unknown format in arg%d spec", i); #endif } + upp->sargc = i; } /* @@ -1445,7 +1446,7 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) dtrace_hdl_t *dtp = pcb->pcb_hdl; dt_irlist_t *dlp = &pcb->pcb_ir; const dt_probe_t *uprp = pcb->pcb_probe; - const dt_uprobe_t *upp = uprp->prv_data; + dt_uprobe_t *upp = uprp->prv_data; const list_probe_t *pop; uint_t lbl_exit = pcb->pcb_exitlbl; dt_ident_t *usdt_prids = dt_dlib_get_map(dtp, "usdt_prids"); @@ -1519,7 +1520,7 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) if (upp->flags & PP_IS_RETURN) goto out; - if (upp->sargc) + if (upp->sargv) copy_args(pcb, upp); else dt_cg_tramp_copy_args_from_regs(pcb, 0); -- 2.43.5 From alan.maguire at oracle.com Mon Jun 23 10:13:07 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Mon, 23 Jun 2025 11:13:07 +0100 Subject: [DTrace-devel] [PATCH v4 2/5] support stapsdt ELF-note-defined static probes In-Reply-To: <20250623101310.1649756-1-alan.maguire@oracle.com> References: <20250623101310.1649756-1-alan.maguire@oracle.com> Message-ID: <20250623101310.1649756-3-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 binaries from /proc/ maps associated with processes and parse them to retrieve uprobe address and argument-related info to create the associated uprobe. Probe arguments can be either constants, register values or dereferences or dereferences from register values (plus offset), identical to the updated USDT ELF note handling. A new provider - stapsdt - implements this support, as stapsdt probes do not dynamically register themselves with DTrace. This makes them less powerful than DTrace-based USDT probes, but they do exist in programs and libraries so should be supported. 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 | 1 + libdtrace/dt_pid.c | 288 +++++++++++++++++++++++++++++++++++++ libdtrace/dt_prov_uprobe.c | 43 +++++- 3 files changed, 328 insertions(+), 4 deletions(-) diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h index 8d4b6432..99093bc9 100644 --- a/include/dtrace/pid.h +++ b/include/dtrace/pid.h @@ -24,6 +24,7 @@ typedef enum pid_probetype { DTPPT_OFFSETS, DTPPT_ABSOFFSETS, DTPPT_USDT, + DTPPT_STAPSDT, DTPPT_IS_ENABLED } pid_probetype_t; diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c index d12b7919..6581b087 100644 --- a/libdtrace/dt_pid.c +++ b/libdtrace/dt_pid.c @@ -38,6 +38,9 @@ #include #include +#define SEC_STAPSDT_NOTE ".note.stapsdt" +#define NAME_STAPSDT_NOTE "stapsdt" + /* * Information on a PID probe. */ @@ -1262,6 +1265,288 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *p return err; } +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 = NULL; + 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, err = 0; + int fd = -1; + char *mod; + + 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); + err = -1; + goto out; + } + } + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + char *secname; + + 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; + + if (strncmp(dbuf + noff, NAME_STAPSDT_NOTE, nhdr.n_namesz) != 0) + continue; + prv = dbuf + doff + (3*sizeof(long)); + /* ensure prv/prb is null-terminated */ + if (strlen(prv) >= nhdr.n_descsz) + continue; + prb = prv + strlen(prv) + 1; + if (strlen(prb) >= nhdr.n_descsz) + continue; + if (strncmp(pdp->prv, prv, strlen(prv)) != 0) + continue; + /* skip unmatched, non-wildcarded probes */ + if (strcmp(pdp->prb, "*") != 0 && + (strlen(pdp->prb) > 0 && strcmp(pdp->prb, prb) != 0)) + continue; + if (prb + strlen(prb) + 1 < dbuf + doff + nhdr.n_descsz) + psp.pps_sargv = prb + strlen(prb) + 1; + + psp.pps_type = DTPPT_STAPSDT; + 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); + err = -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; + + 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))); + err = -1; + } + free(psp.pps_fn); + if (err == -1) + break; + } + +out: + elf_end(elf); + close(fd); + return err; +} + +static void +dt_pid_create_stapsdt_probes_proc(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, + dt_pcb_t *pcb, const dt_provider_t *pvp, + dt_proc_t *dpr, const char *proc_map) +{ + char line[1024]; + FILE *fp = NULL; + pid_t pid; + + assert(dpr != NULL); + + pid = dpr->dpr_pid; + fp = fopen(proc_map, "r"); + if (!fp) + return; + + 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 path[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)"); + if (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) + break; + } + } else { + if (dt_stapsdt_parse(dtp, dpr, pdp, pcb, pvp, name, + addr_start) != 0) + break; + } + } + fclose(fp); +} + +static int +dt_pid_create_stapsdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb) +{ + int i, nmatches = 0, err = 0; + const dt_provider_t *pvp; + char *globpat = NULL; + const char *pidstr; + glob_t globbuf; + bool wildcard; + pid_t pid; + + assert(pcb != NULL); + + pidstr = &pdp->prv[strlen(pdp->prv)]; + + while (isdigit(*(pidstr - 1)) || *(pidstr - 1) == '*') + pidstr--; + if (strlen(pidstr) == 0) + return 0; + wildcard = strchr(pidstr, '*'); + asprintf(&globpat, "/proc/%s/maps", pidstr); + nmatches = glob(globpat, 0, NULL, &globbuf) ? 0 : globbuf.gl_pathc; + pvp = dt_provider_lookup(dtp, "stapsdt"); + assert(pvp != NULL); + + for (i = 0; i < nmatches; i++) { + dt_proc_t *dpr = NULL; + + pidstr = globbuf.gl_pathv[i] + strlen("/proc/"); + pid = atoll(pidstr); + if (pid <= 0) + continue; + if (dt_proc_grab_lock(dtp, pid, DTRACE_PROC_WAITING | + DTRACE_PROC_SHORTLIVED) < 0) { + if (wildcard) + continue; + dt_pid_error(dtp, pcb, NULL, D_PROC_GRAB, + "failed to grab process %d", + (int)pid); + err = 1; + break; + } + dpr = dt_proc_lookup(dtp, pid); + if (dpr) { + dt_pid_create_stapsdt_probes_proc(pdp, dtp, pcb, + pvp, dpr, + globbuf.gl_pathv[i]); + dt_proc_release_unlock(dtp, pid); + } + } + free(globpat); + globfree(&globbuf); + + return err; +} + int dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb) { @@ -1319,6 +1604,9 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t * free(globpat); globfree(&globbuf); + if (err == 0) + 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 2cbd8910..b91cf810 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -313,12 +313,15 @@ static const dtrace_pattr_t pattr = { dt_provimpl_t dt_pid; dt_provimpl_t dt_usdt; +dt_provimpl_t dt_stapsdt; static int populate(dtrace_hdl_t *dtp) { if (dt_provider_create(dtp, dt_uprobe.name, &dt_uprobe, &pattr, NULL) == NULL || dt_provider_create(dtp, dt_pid.name, &dt_pid, &pattr, + NULL) == NULL || + dt_provider_create(dtp, dt_stapsdt.name, &dt_stapsdt, &pattr, NULL) == NULL) return -1; /* errno already set */ @@ -477,8 +480,8 @@ clean_usdt_probes(dtrace_hdl_t *dtp) prp_next = dt_list_next(prp); - /* Make sure it is an overlying USDT probe. */ - if (prp->prov->impl != &dt_usdt) + /* Make sure it is an overlying USDT, stapsdt probe. */ + if (prp->prov->impl != &dt_usdt && prp->prov->impl != &dt_stapsdt) continue; /* FIXME passing in NULL pcb and dpr wreaks havoc on error reporting? */ @@ -637,6 +640,7 @@ static int add_probe_uprobe(dtrace_hdl_t *dtp, dt_probe_t *prp) return 0; } +/* shared between usdt, stapsdt probes */ static int add_probe_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp) { char probnam[DTRACE_FULLNAMELEN], *p; @@ -890,6 +894,7 @@ static dt_probe_t *create_underlying(dtrace_hdl_t *dtp, case DTPPT_OFFSETS: case DTPPT_ABSOFFSETS: case DTPPT_USDT: + case DTPPT_STAPSDT: snprintf(prb, sizeof(prb), "%lx", psp->pps_off); break; default: @@ -904,7 +909,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; @@ -1108,11 +1113,24 @@ static int provide_usdt_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp) return provide_probe(dtp, psp, psp->pps_prb, &dt_usdt, PP_IS_FUNCALL); } +static int provide_stapsdt_probe(dtrace_hdl_t *dtp, const pid_probespec_t *psp) +{ + if (psp->pps_type != DTPPT_STAPSDT && + psp->pps_type != DTPPT_IS_ENABLED) { + dt_dprintf("pid: unknown stapsdt probe type %i\n", psp->pps_type); + return -1; + } + + return provide_probe(dtp, psp, psp->pps_prb, &dt_stapsdt, PP_IS_FUNCALL); +} + + static void enable(dtrace_hdl_t *dtp, dt_probe_t *prp, int is_usdt) { const list_probe_t *pup; - assert(prp->prov->impl == &dt_pid || prp->prov->impl == &dt_usdt); + assert(prp->prov->impl == &dt_pid || prp->prov->impl == &dt_usdt || + prp->prov->impl == &dt_stapsdt); /* * We need to enable the underlying probes (if not enabled yet). @@ -1144,6 +1162,11 @@ static void enable_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp) enable(dtp, prp, 1); } +static void enable_stapsdt(dtrace_hdl_t *dtp, dt_probe_t *prp) +{ + enable(dtp, prp, 1); +} + /* * Generate code that populates, counts the probe arguments. */ @@ -1875,3 +1898,15 @@ dt_provimpl_t dt_usdt = { .discover = &discover, .add_probe = &add_probe_usdt, }; + +/* + * Used for stapsdt probes. + */ +dt_provimpl_t dt_stapsdt = { + .name = "stapsdt", + .prog_type = BPF_PROG_TYPE_UNSPEC, + .provide_probe = &provide_stapsdt_probe, + .enable = &enable_stapsdt, + .probe_destroy = &probe_destroy, + .add_probe = &add_probe_usdt, +}; -- 2.43.5 From alan.maguire at oracle.com Mon Jun 23 10:13:08 2025 From: alan.maguire at oracle.com (Alan Maguire) Date: Mon, 23 Jun 2025 11:13:08 +0100 Subject: [DTrace-devel] [PATCH v4 3/5] selftests/usdt: add test for stapsdt note-defined probe firing, args In-Reply-To: <20250623101310.1649756-1-alan.maguire@oracle.com> References: <20250623101310.1649756-1-alan.maguire@oracle.com> Message-ID: <20250623101310.1649756-4-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: <20250623101310.1649756-1-alan.maguire@oracle.com> Message-ID: <20250623101310.1649756-5-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..c85121c4 --- /dev/null +++ b/test/unittest/usdt/tst.stapsdt-notes-lib.r @@ -0,0 +1,14 @@ +libstapsdttest.so:zero +libstapsdttest.so:one:1 +libstapsdttest.so:two:2:3 +libstapsdttest.so:three:4:5:7 +libstapsdttest.so:four:7:8:9:10 +libstapsdttest.so:five:11:12:13:14:15 +libstapsdttest.so:six:16:17:18:19:20:21 +libstapsdttest.so:seven:22:23:24:25:26:27:28 +libstapsdttest.so:eight:29:30:31:32:33:34:35:36 +libstapsdttest.so:nine:37:38:39:40:41:42:43:44:45 +libstapsdttest.so:ten:46:47:48:49:50:51:52:53:54:55 +libstapsdttest.so:eleven:56:57:58:59:60:61:62:63:64:65 +libstapsdttest.so: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..bb4ed1cc --- /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: <20250623101310.1649756-1-alan.maguire@oracle.com> Message-ID: <20250623101310.1649756-6-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 < (Kris Van Hees's message of "Thu, 19 Jun 2025 12:32:13 -0400") References: <20250522180118.27343-1-eugene.loh@oracle.com> <87sek3d83m.fsf@esperi.org.uk> <6cdb7118-e678-57e7-adff-a74a1ff39e19@oracle.com> <87jz57zxvn.fsf@esperi.org.uk> Message-ID: <87o6uey2pb.fsf@esperi.org.uk> On 19 Jun 2025, Kris Van Hees uttered the following: > On Thu, Jun 19, 2025 at 12:20:22PM -0400, Kris Van Hees wrote: >> On Thu, Jun 19, 2025 at 02:03:56PM +0100, Nick Alcock wrote: >> > On 16 Jun 2025, Eugene Loh verbalised: >> > >> > > On 6/13/25 10:33, Nick Alcock wrote: >> > > >> > >>> Note that we declare the skip count volatile. The compiler might >> > >>> optimize code that uses the STACK_SKIP value, but we will subsequently >> > >>> perform relocations that adjust this value. >> > >> ... why doesn't this apply to every other extern global variable in >> > >> get_bvar()? They're all similarly relocated... >> > > >> > > Right.? There is potentially a broader problem.? But we simply do not have evidence of misbehavior in other cases.? Ruggedizing >> > > other cases could be the subject of a different patch. >> > >> > Aha, OK. I was just wondering if there was some extra reason. >> > >> > > The problem in this case is that the compiler seems to assume &symbol!=0, which is reasonable except that we violate that behavior >> > > for our relocation tricks. >> > >> > I wonder where the code for that is... plenty of symbols have value >> > zero. >> > >> > But, really... >> > >> > > Consider the C code: >> > > >> > > ??? 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); >> > >> > Hm... >> > >> > extern uint64_t STACK_SKIP; >> > >> > So we encode information about the stack size and skip value by encoding >> > it in the *address* of the variable? Is there some reason we don't use >> > its value? unlike the stack offset, we're *using* it as a value, not an >> > address... >> >> The issue seems to be (and perhaps this is a cross compiler problem) that e.g. >> >> extern uint64_t PC; >> >> and then code accessing the value of PC (e.g. foo(PC) as a call argument) will >> yield: >> >> 50: 18 02 00 00 00 00 00 00 lddw %r2,0 >> 58: 00 00 00 00 00 00 00 00 >> 50: R_BPF_INSN_64 PC >> 60: 79 22 00 00 00 00 00 00 ldxdw %r2,[%r2+0] >> >> which shows that it is interpreting PC as an address to a symbol, because it >> loads the address of the symbol and then dereferences it with offset 0. So, >> we cannot plug in the value during relocation because the only value we can >> put there would be an address where the vlaue can be found. To get around >> this, we "use" Tthe address as the entity to store the value in, knowing that >> we *never* will interpret it as an address for these specific externs. > > Not a compiler error - since PC is extern uint64_t PC it *is* a variable and > so it is present (and accessible) as an address in .data in the location where > it is actually defined. Since we never define it, we don't have a .data (which > is fine because we only use this for constants known at link time) BUT the > compiler of course is free to assume that we *do* have an address to the > storage location for PC and thus that we get the value that way. It does not > know that the value is constant. So, the trick I use is needed to make this > work. I'm just not sure why it's assuming that its value cannot be NULL, given that you're not dereferencing it anywhere. I guess it's because it's a symbol, but that's only a guess: I haven't managed to find the code that implements this (?)optimization. Anyway, this is not an objection to this patch, and a patch changing this approach to something that didn't require us to throw volatiles around and hope the compiler doesn't optimize things wrong would be a separate patch anyway: you have my Revieed-by: Nick Alcock From eugene.loh at oracle.com Mon Jun 23 20:33:28 2025 From: eugene.loh at oracle.com (Eugene Loh) Date: Mon, 23 Jun 2025 16:33:28 -0400 Subject: [DTrace-devel] [PATCH] test: Suppress some white space In-Reply-To: <87cyb7enqu.fsf@esperi.org.uk> References: <20250609180647.4424-1-eugene.loh@oracle.com> <87cyb7enqu.fsf@esperi.org.uk> Message-ID: <10ca48a3-7e72-f0dd-4fdc-72baf3d52ac6@oracle.com> On 6/13/25 10:10, Nick Alcock wrote: > On 9 Jun 2025, eugene loh spake thusly: > >> From: Eugene Loh >> >> The test suite turns pointers into "{ptr}" so that results >> comparisons will not be sensitive to particular pointer offset >> values. >> >> If these offsets change in width -- say, from 0xf0 to 0x100 -- >> the amount of white space in the postprocessed output can change. >> >> Add additional postprocessing to a test that sometimes fails due >> to this problem. > Hmm... this would work for this test, but maybe we should change the > {ptr} substitution in runtest.sh itself so that it gets this right in > the general case? > > Something like > > diff --git a/runtest.sh b/runtest.sh > index 156e7dec8a1c3..c5703a81bc6d4 100755 > --- a/runtest.sh > +++ b/runtest.sh > @@ -509,7 +509,7 @@ postprocess() > # TODO: may need adjustment or making optional if scripts emit hex > # values which are not continuously variable. > > - sed -e '/^==[0-9][0-9]*== /!s,0x[0-9a-f][0-9a-f]*,{ptr},g' \ > + sed -e '/^==[0-9][0-9]*== /!s,0x[0-9a-f][0-9a-f]*\([ \t]*\),{ptr}\1,g' \ > -e 's,at BPF pc [1-9][0-9]*,at BPF pc NNN,' < $tmpdir/pp.out > $final > > return $retval > > might work. (Obviously the lines would no longer line up, but the number > of spaces would remain the same as they were before the substitution.) > > Lots and lots of expected results would need regenerating after this, > of course... I agree that one can make a case for a broader change, but I'm not convinced that that would be the better way.? FWIW, there were these two commits ??????? 6f398f229 test: Make tests more resilient to different prid widths ??????? 72a79b784 test: Improve resilience of tests to ptr widths that took the narrower, more tactical approach to such a problem. I vote for the expedient route:? a "Reviewed-by" and we move on. But then, in this case, my vote doesn't count! From kris.van.hees at oracle.com Mon Jun 23 23:37:17 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Mon, 23 Jun 2025 19:37:17 -0400 Subject: [DTrace-devel] [PATCH 1/3] options: add -xbtfpath option Message-ID: Also move the initialization of BPF and BTF to dtrace_init() to ensure that the -xbtfpath= option is processed before we try to access BTF data. Signed-off-by: Kris Van Hees --- libdtrace/dt_btf.c | 22 ++++++++++++++++++++-- libdtrace/dt_impl.h | 1 + libdtrace/dt_open.c | 10 +++++++--- libdtrace/dt_options.c | 21 +++++++++++++++++++++ 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/libdtrace/dt_btf.c b/libdtrace/dt_btf.c index ad87bd83..e9ead435 100644 --- a/libdtrace/dt_btf.c +++ b/libdtrace/dt_btf.c @@ -337,6 +337,8 @@ dt_btf_load_file(dtrace_hdl_t *dtp, const char *fn) return NULL; } + dt_dprintf("BTF file %s: %d types\n", fn, btf->type_cnt); + return btf; } @@ -765,14 +767,30 @@ out: dt_btf_t * dt_btf_load_module(dtrace_hdl_t *dtp, dt_module_t *dmp) { - char fn[PATH_MAX + 1]; + char *fn = NULL; + int rc = 0; dt_btf_t *btf; if (dmp->dm_btf) return dmp->dm_btf; - snprintf(fn, sizeof(fn), "/sys/kernel/btf/%s", dmp->dm_name); + /* + * Default: /sys/kernel/btf/ + * If "none", disable BTF. + * Otherwise: / + */ + if (dtp->dt_btf_path == NULL) + rc = asprintf(&fn, "/sys/kernel/btf/%s", dmp->dm_name); + else if (strcmp(dtp->dt_btf_path, "none") == 0) + return NULL; + else + rc = asprintf(&fn, "%s/%s", dtp->dt_btf_path, dmp->dm_name); + + if (rc == -1) + return dt_btf_set_load_errno(dtp, ENOMEM); + btf = dt_btf_load_file(dtp, fn); + free(fn); if (btf && !dtp->dt_shared_btf && strcmp(dmp->dm_name, "vmlinux") == 0) dtp->dt_shared_btf = btf; diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h index 3bb7c344..2adc1252 100644 --- a/libdtrace/dt_impl.h +++ b/libdtrace/dt_impl.h @@ -301,6 +301,7 @@ struct dtrace_hdl { dt_htab_t *dt_kernsyms; /* htab of kernel symbol names */ char *dt_ctfa_path; /* path to vmlinux.ctfa */ ctf_archive_t *dt_ctfa; /* ctf archive for the entire kernel tree */ + char *dt_btf_path; /* path to vmlinux.btf */ struct dt_btf *dt_shared_btf; /* BTF data for the kernel (shared) */ ctf_file_t *dt_shared_ctf; /* Handle to the shared CTF */ dt_htab_t *dt_kernpaths; /* hash table of dt_kern_path_t's */ diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c index 01c36a76..c67455e7 100644 --- a/libdtrace/dt_open.c +++ b/libdtrace/dt_open.c @@ -910,6 +910,11 @@ dt_vopen(int version, int flags, int *errp, return set_open_errno(dtp, errp, EDT_NOMEM); } + /* If DTRACE_OPT_BTFPATH is set, use it. */ + dtp->dt_btf_path = getenv("DTRACE_OPT_BTFPATH"); + if (dtp->dt_btf_path) + dtp->dt_btf_path = strdup(dtp->dt_btf_path); + /* * Update the module list and load the values for the macro variable * definitions according to the current process. @@ -1146,9 +1151,6 @@ dt_vopen(int version, int flags, int *errp, if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0) return set_open_errno(dtp, errp, dtp->dt_errno); - dt_bpf_init(dtp); - dt_btf_get_module_ids(dtp); - return dtp; } @@ -1181,6 +1183,8 @@ dtrace_init(dtrace_hdl_t *dtp) /* * Initialize the BPF library handling. */ + dt_bpf_init(dtp); + dt_btf_get_module_ids(dtp); dt_dlib_init(dtp); /* diff --git a/libdtrace/dt_options.c b/libdtrace/dt_options.c index 377b396b..25e79979 100644 --- a/libdtrace/dt_options.c +++ b/libdtrace/dt_options.c @@ -303,6 +303,26 @@ dt_opt_ld_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) return 0; } +static int +dt_opt_btf_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) +{ + char *btf; + + if (arg == NULL) + return dt_set_errno(dtp, EDT_BADOPTVAL); + + if (dtp->dt_pcb != NULL) + return dt_set_errno(dtp, EDT_BADOPTCTX); + + if ((btf = strdup(arg)) == NULL) + return dt_set_errno(dtp, EDT_NOMEM); + + free(dtp->dt_btf_path); + dtp->dt_btf_path = btf; + + return 0; +} + static int dt_opt_ctfa_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option) { @@ -1067,6 +1087,7 @@ static const dt_option_t _dtrace_ctoptions[] = { { "aggpercpu", dt_opt_agg, DTRACE_A_PERCPU }, { "amin", dt_opt_amin }, { "argref", dt_opt_cflags, DTRACE_C_ARGREF }, + { "btfpath", dt_opt_btf_path }, { "core", dt_opt_core }, { "cpp", dt_opt_cflags, DTRACE_C_CPP }, { "cppargs", dt_opt_cpp_args }, -- 2.43.5 From kris.van.hees at oracle.com Mon Jun 23 23:37:19 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Mon, 23 Jun 2025 19:37:19 -0400 Subject: [DTrace-devel] [PATCH 2/3] btf: do not try to generate CTF data if there is no BTF data Message-ID: Signed-off-by: Kris Van Hees --- libdtrace/dt_module.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/libdtrace/dt_module.c b/libdtrace/dt_module.c index b3c8e247..eef5386a 100644 --- a/libdtrace/dt_module.c +++ b/libdtrace/dt_module.c @@ -864,11 +864,12 @@ static void dt_kern_module_find_btf(dtrace_hdl_t *dtp, dt_module_t *dmp) { /* - * The first module for which we need to collect BTF data must be the - * 'vmlinux' module. + * If there is no shared BTF data, and we're trying to load BTF data + * fir any module other than "vmlinux", we can conclude no module has + * valid BTF data. */ - if (dtp->dt_shared_btf == NULL) - assert(strcmp(dmp->dm_name, "vmlinux") == 0); + if (dtp->dt_shared_btf == NULL && strcmp(dmp->dm_name, "vmlinux") != 0) + return; dt_dprintf("Loading BTF for module %s.\n", dmp->dm_name); @@ -957,8 +958,12 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp) * data for shared_ctf from. */ mod = dt_module_lookup_by_name(dtp, "vmlinux"); - dt_kern_module_ctf_from_btf(dtp, mod); - dtp->dt_shared_ctf = mod->dm_ctfp; + if (mod->dm_btf != NULL) { + dt_kern_module_ctf_from_btf(dtp, mod); + dtp->dt_shared_ctf = mod->dm_ctfp; + } else + dt_dprintf("No BTF data for vmlinux; " + "looking for in-module CTF instead.\n"); #else dt_dprintf("Cannot open CTF archive %s: %s; " "looking for in-module CTF instead.\n", @@ -1019,11 +1024,14 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp) dmp->dm_flags |= DT_DM_CTF_ARCHIVED; ctf_setspecific(dmp->dm_ctfp, dmp); #ifdef HAVE_LIBCTF - } else { + } else if (dmp->dm_btf != NULL) { /* Generate CTF from BTF for the module. */ dt_kern_module_ctf_from_btf(dtp, dmp); + } else + dt_dprintf("No BTF data for %s; " + "looking for in-module CTF instead.\n", + dmp->dm_name); #endif - } /* * No CTF archive, module not present in it, or module not loaded so -- 2.43.5 From kris.van.hees at oracle.com Mon Jun 23 23:37:21 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Mon, 23 Jun 2025 19:37:21 -0400 Subject: [DTrace-devel] [PATCH 3/3] dlibs: report missing CTF and BTF data for vmlinux Message-ID: If the kernel is not compiled with CTF and/or BTF enabled, DTrace will not work. This used to result in an assert, which is rather harsh and not user friendly. We now report a nice error. Doing this in the pragma 'depends on' handling may seem odd but that is where the initial type data load is triggered. If for some strange reason no dlibs exist (and thus no 'depends on' are encountered), the compiler will complain about missing type information anyway. Signed-off-by: Kris Van Hees --- libdtrace/dt_pragma.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libdtrace/dt_pragma.c b/libdtrace/dt_pragma.c index 0c97edfc..d29e6e28 100644 --- a/libdtrace/dt_pragma.c +++ b/libdtrace/dt_pragma.c @@ -202,7 +202,15 @@ dt_pragma_depends(const char *prname, dt_node_t *cnp) found = dt_provider_lookup(dtp, nnp->dn_string) != NULL; else if (strcmp(cnp->dn_string, "module") == 0) { dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string); - found = mp != NULL && dt_module_getctf(dtp, mp) != NULL; + + if (mp == NULL) + found = B_FALSE; + else if (dt_module_getctf(dtp, mp) != NULL) + found = B_TRUE; + else + xyerror(D_SYM_NOTYPES, + "No type data (CTF or BTF) found for %s", + mp->dm_name); } else if (strcmp(cnp->dn_string, "library") == 0) { if (yypcb->pcb_cflags & DTRACE_C_CTL) { assert(dtp->dt_filetag != NULL); -- 2.43.5 From nick.alcock at oracle.com Tue Jun 24 14:14:56 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Tue, 24 Jun 2025 15:14:56 +0100 Subject: [DTrace-devel] [PATCH 1/3] options: add -xbtfpath option In-Reply-To: (Kris Van Hees's message of "Mon, 23 Jun 2025 19:37:17 -0400") References: Message-ID: <875xglql9b.fsf@esperi.org.uk> On 24 Jun 2025, Kris Van Hees outgrape: > Also move the initialization of BPF and BTF to dtrace_init() to ensure > that the -xbtfpath= option is processed before we try to access BTF > data. > > Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock (I've wanted an -xbtfpath= for a while now.) -- NULL && (void) From nick.alcock at oracle.com Tue Jun 24 14:16:32 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Tue, 24 Jun 2025 15:16:32 +0100 Subject: [DTrace-devel] [PATCH 2/3] btf: do not try to generate CTF data if there is no BTF data In-Reply-To: (Kris Van Hees's message of "Mon, 23 Jun 2025 19:37:19 -0400") References: Message-ID: <871pr9ql6n.fsf@esperi.org.uk> On 24 Jun 2025, Kris Van Hees outgrape: > Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock modulo the spelling nit below. > --- > libdtrace/dt_module.c | 24 ++++++++++++++++-------- > 1 file changed, 16 insertions(+), 8 deletions(-) > > diff --git a/libdtrace/dt_module.c b/libdtrace/dt_module.c > index b3c8e247..eef5386a 100644 > --- a/libdtrace/dt_module.c > +++ b/libdtrace/dt_module.c > @@ -864,11 +864,12 @@ static void > dt_kern_module_find_btf(dtrace_hdl_t *dtp, dt_module_t *dmp) > { > /* > - * The first module for which we need to collect BTF data must be the > - * 'vmlinux' module. > + * If there is no shared BTF data, and we're trying to load BTF data > + * fir any module other than "vmlinux", we can conclude no module has s/fir/for/ -- NULL && (void) From nick.alcock at oracle.com Tue Jun 24 14:18:47 2025 From: nick.alcock at oracle.com (Nick Alcock) Date: Tue, 24 Jun 2025 15:18:47 +0100 Subject: [DTrace-devel] [PATCH 3/3] dlibs: report missing CTF and BTF data for vmlinux In-Reply-To: (Kris Van Hees via DTrace-devel's message of "Mon, 23 Jun 2025 19:37:21 -0400") References: Message-ID: <87wm91p6ig.fsf@esperi.org.uk> On 24 Jun 2025, Kris Van Hees via DTrace-devel spake thusly: > If the kernel is not compiled with CTF and/or BTF enabled, DTrace will > not work. This used to result in an assert, which is rather harsh and > not user friendly. We now report a nice error. > > Doing this in the pragma 'depends on' handling may seem odd but that is > where the initial type data load is triggered. If for some strange > reason no dlibs exist (and thus no 'depends on' are encountered), the > compiler will complain about missing type information anyway. I'm honestly wondering if we should do a type lookup for something trivial that will always be present in a hardwired fashion, so we don't have to depend on a side effect this delicate (which will fail the first time a .d is introduced which sorts lexicographically before any existing one, depends on any types other than the built-in ones -- which is why errno.d doesn't trigger a type lookup -- and does not start with #pragma D depends_on module vmlinux like io.d happens to.) > Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock even if I think this feels wrong, it does work... From kris.van.hees at oracle.com Tue Jun 24 14:49:43 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 24 Jun 2025 10:49:43 -0400 Subject: [DTrace-devel] [PATCH 3/3] dlibs: report missing CTF and BTF data for vmlinux In-Reply-To: <87wm91p6ig.fsf@esperi.org.uk> References: <87wm91p6ig.fsf@esperi.org.uk> Message-ID: On Tue, Jun 24, 2025 at 03:18:47PM +0100, Nick Alcock wrote: > On 24 Jun 2025, Kris Van Hees via DTrace-devel spake thusly: > > > If the kernel is not compiled with CTF and/or BTF enabled, DTrace will > > not work. This used to result in an assert, which is rather harsh and > > not user friendly. We now report a nice error. > > > > Doing this in the pragma 'depends on' handling may seem odd but that is > > where the initial type data load is triggered. If for some strange > > reason no dlibs exist (and thus no 'depends on' are encountered), the > > compiler will complain about missing type information anyway. > > I'm honestly wondering if we should do a type lookup for something > trivial that will always be present in a hardwired fashion, so we don't > have to depend on a side effect this delicate (which will fail the first > time a .d is introduced which sorts lexicographically before any > existing one, depends on any types other than the built-in ones -- which > is why errno.d doesn't trigger a type lookup -- and does not start with > > #pragma D depends_on module vmlinux > > like io.d happens to.) That is why I wrote that 2nd paragraph, right? If a .d file depends on any other module, it will still report an error: No type data (CTF or BTF) found for And if there are no dependencies (or e.g. the extreme case of no dlibs), you still get a nice error, e.g. if you use curthread and there is no type data and no dlibs to trigger the error report this patch adds: failed to resolve type vmlinux`struct task_struct * for identifier curthread: Cannot read object file or modules.dep That is because of patch 2/3 ensuring that we do not bail with an assert, but instead let error reporting do its work. > > Signed-off-by: Kris Van Hees > > Reviewed-by: Nick Alcock > > even if I think this feels wrong, it does work... From kris.van.hees at oracle.com Tue Jun 24 21:40:23 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 24 Jun 2025 17:40:23 -0400 Subject: [DTrace-devel] [PATCH 1/3] usdt parser: remove left-over debug statement Message-ID: Signed-off-by: Kris Van Hees --- libcommon/usdt_parser_notes.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libcommon/usdt_parser_notes.c b/libcommon/usdt_parser_notes.c index 0b0e1a7a..fb57f119 100644 --- a/libcommon/usdt_parser_notes.c +++ b/libcommon/usdt_parser_notes.c @@ -287,7 +287,6 @@ strarray_size(uint8_t cnt, const char *str, const char *end, size_t skip) if (p >= end) return -1; -dt_dbg_usdt("%s: [%s] [%hhd]\n", __func__, p, *(p + strlen(p) + 1)); p += strlen(p) + 1 + skip; } -- 2.43.5 From kris.van.hees at oracle.com Tue Jun 24 21:40:25 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 24 Jun 2025 17:40:25 -0400 Subject: [DTrace-devel] [PATCH 2/3] usdt parser: handle encoded hyphens Message-ID: Signed-off-by: Kris Van Hees --- libcommon/usdt_parser_notes.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/libcommon/usdt_parser_notes.c b/libcommon/usdt_parser_notes.c index fb57f119..d3d744fb 100644 --- a/libcommon/usdt_parser_notes.c +++ b/libcommon/usdt_parser_notes.c @@ -471,6 +471,23 @@ parse_usdt_note(int out, dof_helper_t *dhp, usdt_data_t *data, } prbt.off = off; + /* + * If the probe name has encoded hyphens, perform in-place changing + * from "__" into "-". + */ + if (strstr(prbt.prb, "__") != NULL) { + char *q; + const char *s = prbt.prb, *e = p; + + for (q = (char *)s; s < e; s++, q++) { + if (s[0] == '_' && s[1] == '_') { + *q = '-'; + s++; + } else if (s > q) + *q = *s; + } + } + if ((prp = dt_htab_lookup(prbmap, &prbt)) == NULL) { if ((prp = malloc(sizeof(dt_probe_t))) == NULL) { usdt_error(out, ENOMEM, "Failed to allocate probe"); -- 2.43.5 From kris.van.hees at oracle.com Tue Jun 24 21:40:27 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Tue, 24 Jun 2025 17:40:27 -0400 Subject: [DTrace-devel] [PATCH 3/3] usdt parser: make sure prbmap is cleaned up in case of error Message-ID: Signed-off-by: Kris Van Hees --- libcommon/usdt_parser_notes.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libcommon/usdt_parser_notes.c b/libcommon/usdt_parser_notes.c index d3d744fb..c98c9fb0 100644 --- a/libcommon/usdt_parser_notes.c +++ b/libcommon/usdt_parser_notes.c @@ -829,15 +829,16 @@ usdt_parse_notes(int out, dof_helper_t *dhp, usdt_data_t *data) goto out; err: - rc = -1; - -out: /* - * All tracepoint probes in prbmap should have been removed during - * proessing. + * In case of an error, we don't know whether we can allocate iterators + * so we have few options to provide cleanup. Since cleanup is all we + * do now, we plug the probe cleanup function into the ops for prbmap, + * and let the hashtable destroy function take care of all cleanup. */ - assert(dt_htab_entries(prbmap) == 0); + prb_htab_ops.del = (htab_del_fn)prb_del_probe; + rc = -1; +out: dt_htab_destroy(prvmap); dt_htab_destroy(prbmap); -- 2.43.5 From noreply at github.com Wed Jun 25 04:01:39 2025 From: noreply at github.com (Kris Van Hees) Date: Tue, 24 Jun 2025 21:01:39 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] a5903f: options: add -xbtfpath option Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: a5903f518dc1ad5d634f56e06fdbb56df0913f11 https://github.com/oracle/dtrace-utils/commit/a5903f518dc1ad5d634f56e06fdbb56df0913f11 Author: Kris Van Hees Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: M libdtrace/dt_btf.c M libdtrace/dt_impl.h M libdtrace/dt_open.c M libdtrace/dt_options.c Log Message: ----------- options: add -xbtfpath option Also move the initialization of BPF and BTF to dtrace_init() to ensure that the -xbtfpath= option is processed before we try to access BTF data. Use -xbtfpath=none to disable the use of BTF data. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: 59063c82621356360b5d6c71430530c385b47316 https://github.com/oracle/dtrace-utils/commit/59063c82621356360b5d6c71430530c385b47316 Author: Kris Van Hees Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: M libdtrace/dt_module.c Log Message: ----------- btf: do not try to generate CTF data if there is no BTF data Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Commit: f0e1424fa41b50b0c9382b2d7e2012a3c6fdbb8a https://github.com/oracle/dtrace-utils/commit/f0e1424fa41b50b0c9382b2d7e2012a3c6fdbb8a Author: Kris Van Hees Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: M libdtrace/dt_pragma.c Log Message: ----------- dlibs: report missing CTF and BTF data for vmlinux If the kernel is not compiled with CTF and/or BTF enabled, DTrace will not work. This used to result in an assert, which is rather harsh and not user friendly. We now report a nice error. Doing this in the pragma 'depends on' handling may seem odd but that is where the initial type data load is triggered. If for some strange reason no dlibs exist (and thus no 'depends on' are encountered), the compiler will complain about missing type information anyway. Signed-off-by: Kris Van Hees Reviewed-by: Nick Alcock Compare: https://github.com/oracle/dtrace-utils/compare/23cdaf54ce75...f0e1424fa41b 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 Wed Jun 25 04:18:34 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Wed, 25 Jun 2025 00:18:34 -0400 Subject: [DTrace-devel] [PATCH 11/14] Test: caller and stackdepth tests for proc provider In-Reply-To: <4e0a07a6-04a0-3d60-af59-ba32a41a03f6@oracle.com> References: <20250522180118.27343-1-eugene.loh@oracle.com> <20250522180118.27343-11-eugene.loh@oracle.com> <87ikkzbsmb.fsf@esperi.org.uk> <4e0a07a6-04a0-3d60-af59-ba32a41a03f6@oracle.com> Message-ID: On Sun, Jun 15, 2025 at 01:50:02PM -0400, Eugene Loh wrote: > Thanks. > > I'm getting to these out of order, but I figured I'd mention that I'm going > to turn the capitalized "Test:" into "test:" for this series of patches to > conform to the style in related patches. In that case, please post v2 of the series ASAP because I cannot merge without updated patches. > > On 6/13/25 10:53, Nick Alcock wrote: > > On 22 May 2025, eugene loh told this: > > > > > From: Eugene Loh > > > > > > Signed-off-by: Eugene Loh > > Reviewed-by: Nick Alcock > > From eugene.loh at oracle.com Wed Jun 25 04:20:56 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:20:56 -0400 Subject: [DTrace-devel] [PATCH v2 03/14] test: remove unnecessary "unstable" tag In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-3-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- test/unittest/sched/tst.stackdepth.d | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unittest/sched/tst.stackdepth.d b/test/unittest/sched/tst.stackdepth.d index 02a878bea..e6ffca01c 100644 --- a/test/unittest/sched/tst.stackdepth.d +++ b/test/unittest/sched/tst.stackdepth.d @@ -4,7 +4,6 @@ * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ -/* @@tags: unstable */ #pragma D option switchrate=100hz -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:20:57 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:20:57 -0400 Subject: [DTrace-devel] [PATCH v2 04/14] test: caller and stackdepth tests for fbt provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-4-eugene.loh@oracle.com> From: Eugene Loh We will introduce a set of tests for the caller and stackdepth built-in variables for a wide selection of providers. For the caller test, we will essentially call stack(2); sym(caller); and then compare the caller to the second stack frame using the new script check_caller_to_stack2.awk. For the stackdepth test, we will essentially call printf("%d\n", stackdepth); stack(); and then compare the stackdepth to the reported frames using the new script check_stackdepth_to_stack.awk. In this patch, introduce tests for the fbt provider, along with the support scripts they need. Subsequent patches will handle other providers. The old tst.caller2.d and tst.stackdepth2.d, which tested fbt, become obsolete. Remove them. Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- .../variables/bvar/check_caller_to_stack2.awk | 32 +++++++++++++++++ ...pth2.r.p => check_stackdepth_to_stack.awk} | 16 ++++++--- test/unittest/variables/bvar/tst.caller-fbt.d | 26 ++++++++++++++ test/unittest/variables/bvar/tst.caller-fbt.r | 1 + .../variables/bvar/tst.caller-fbt.r.p | 1 + test/unittest/variables/bvar/tst.caller2.d | 31 ---------------- test/unittest/variables/bvar/tst.caller2.r | 1 - test/unittest/variables/bvar/tst.caller2.r.p | 11 ------ .../variables/bvar/tst.stackdepth-fbt.d | 28 +++++++++++++++ ...tst.stackdepth2.r => tst.stackdepth-fbt.r} | 0 .../variables/bvar/tst.stackdepth-fbt.r.p | 1 + .../unittest/variables/bvar/tst.stackdepth2.d | 36 ------------------- 12 files changed, 101 insertions(+), 83 deletions(-) create mode 100755 test/unittest/variables/bvar/check_caller_to_stack2.awk rename test/unittest/variables/bvar/{tst.stackdepth2.r.p => check_stackdepth_to_stack.awk} (63%) create mode 100644 test/unittest/variables/bvar/tst.caller-fbt.d create mode 100644 test/unittest/variables/bvar/tst.caller-fbt.r create mode 120000 test/unittest/variables/bvar/tst.caller-fbt.r.p delete mode 100644 test/unittest/variables/bvar/tst.caller2.d delete mode 100644 test/unittest/variables/bvar/tst.caller2.r delete mode 100755 test/unittest/variables/bvar/tst.caller2.r.p create mode 100644 test/unittest/variables/bvar/tst.stackdepth-fbt.d rename test/unittest/variables/bvar/{tst.stackdepth2.r => tst.stackdepth-fbt.r} (100%) create mode 120000 test/unittest/variables/bvar/tst.stackdepth-fbt.r.p delete mode 100644 test/unittest/variables/bvar/tst.stackdepth2.d diff --git a/test/unittest/variables/bvar/check_caller_to_stack2.awk b/test/unittest/variables/bvar/check_caller_to_stack2.awk new file mode 100755 index 000000000..8499852a7 --- /dev/null +++ b/test/unittest/variables/bvar/check_caller_to_stack2.awk @@ -0,0 +1,32 @@ +#!/usr/bin/gawk -f + +# Check output of tst.caller-$provider.d tests of the form +# +# { +# stack(2); +# sym(caller); +# } +# +# Confirm that the caller information matches the stack information. + +# Look for the first nonblank line. +NF != 0 { + # It is the current frame. Skip it. + if (getline != 1) { print "ERROR: missing expected output"; exit(1); } + + # Now we have the caller frame. Strip off the offset. + expect=$1 + sub("+0x[0-9a-f]*$", "", expect); + + # Finally, get the sym(caller) output. + if (getline != 1) { print "ERROR: missing expected output"; exit(1); } + + # Compare. + if (expect == $1) { + print "success"; + exit(0); + } else { + print "ERROR: expect", expect, "but got", $1; + exit(1); + } +} diff --git a/test/unittest/variables/bvar/tst.stackdepth2.r.p b/test/unittest/variables/bvar/check_stackdepth_to_stack.awk similarity index 63% rename from test/unittest/variables/bvar/tst.stackdepth2.r.p rename to test/unittest/variables/bvar/check_stackdepth_to_stack.awk index 9b071181f..fba1f4242 100755 --- a/test/unittest/variables/bvar/tst.stackdepth2.r.p +++ b/test/unittest/variables/bvar/check_stackdepth_to_stack.awk @@ -1,8 +1,16 @@ #!/usr/bin/gawk -f -# Oracle Linux DTrace. -# Copyright (c) 2016, 2021, 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. +# +# Check output of tst.stackdepth-$provider.d tests of the form +# +# { +# printf("DEPTH %d\n", stackdepth); +# printf("TRACE BEGIN\n"); +# stack(); +# printf("TRACE END\n"); +# exit(0); +# } +# +# Confirm that the stackdepth information matches the stack information. /^DEPTH/ { depth = int($2); diff --git a/test/unittest/variables/bvar/tst.caller-fbt.d b/test/unittest/variables/bvar/tst.caller-fbt.d new file mode 100644 index 000000000..a81353335 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-fbt.d @@ -0,0 +1,26 @@ +/* + * 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: periodic_output + */ +/* Check that 'caller' is consistent with stack(). */ + +#pragma D option quiet + +fbt::ksys_write:entry +/pid == $target/ +{ + stack(2); + sym(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.caller-fbt.r b/test/unittest/variables/bvar/tst.caller-fbt.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-fbt.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/variables/bvar/tst.caller-fbt.r.p b/test/unittest/variables/bvar/tst.caller-fbt.r.p new file mode 120000 index 000000000..954ca96aa --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-fbt.r.p @@ -0,0 +1 @@ +check_caller_to_stack2.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.caller2.d b/test/unittest/variables/bvar/tst.caller2.d deleted file mode 100644 index ca6dbfd22..000000000 --- a/test/unittest/variables/bvar/tst.caller2.d +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Oracle Linux DTrace. - * Copyright (c) 2021, 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 'caller' should be consistent with stack(). - * - * SECTION: Variables/Built-in Variables/caller - */ - -#pragma D option quiet -#pragma D option destructive - -BEGIN -{ - system("echo write something > /dev/null"); -} - -fbt::ksys_write:entry -{ - stack(2); - sym(caller); - exit(0); -} - -ERROR { - exit(1); -} diff --git a/test/unittest/variables/bvar/tst.caller2.r b/test/unittest/variables/bvar/tst.caller2.r deleted file mode 100644 index 0cfbf0888..000000000 --- a/test/unittest/variables/bvar/tst.caller2.r +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/test/unittest/variables/bvar/tst.caller2.r.p b/test/unittest/variables/bvar/tst.caller2.r.p deleted file mode 100755 index 1a26a4df2..000000000 --- a/test/unittest/variables/bvar/tst.caller2.r.p +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# sed: remove +0x{ptr} offsets -# awk: look for the ksys_write frame, then write the next two lines -# uniq: count unique lines -# awk: report the counts - -sed 's/+0x.*$//' \ -| /usr/bin/gawk '/ksys_write/ {getline; print $1; getline; print $1; exit(0)}' \ -| uniq -c \ -| /usr/bin/gawk '{print $1}' diff --git a/test/unittest/variables/bvar/tst.stackdepth-fbt.d b/test/unittest/variables/bvar/tst.stackdepth-fbt.d new file mode 100644 index 000000000..d33897a5f --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-fbt.d @@ -0,0 +1,28 @@ +/* + * 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: periodic_output + */ +/* Check that 'stackdepth' is consistent with stack(). */ + +#pragma D option quiet + +fbt::ksys_write:entry +/pid == $target/ +{ + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(100); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.stackdepth2.r b/test/unittest/variables/bvar/tst.stackdepth-fbt.r similarity index 100% rename from test/unittest/variables/bvar/tst.stackdepth2.r rename to test/unittest/variables/bvar/tst.stackdepth-fbt.r diff --git a/test/unittest/variables/bvar/tst.stackdepth-fbt.r.p b/test/unittest/variables/bvar/tst.stackdepth-fbt.r.p new file mode 120000 index 000000000..e50f12822 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-fbt.r.p @@ -0,0 +1 @@ +check_stackdepth_to_stack.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth2.d b/test/unittest/variables/bvar/tst.stackdepth2.d deleted file mode 100644 index 2b1c0866a..000000000 --- a/test/unittest/variables/bvar/tst.stackdepth2.d +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Oracle Linux DTrace. - * Copyright (c) 2006, 2021, 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. - */ - -#pragma D option destructive -#pragma D option quiet - -/* - * ASSERTION: - * Test the stackdepth variable. Verify its value against the stack trace. - * - * SECTION: Variables/Built-in Variables - * - */ - -BEGIN -{ - system("echo write something > /dev/null"); -} - -fbt::ksys_write:entry -{ - printf("DEPTH %d\n", stackdepth); - printf("TRACE BEGIN\n"); - stack(); - printf("TRACE END\n"); - exit(0); -} - -ERROR -{ - exit(1); -} -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:20:58 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:20:58 -0400 Subject: [DTrace-devel] [PATCH v2 05/14] test: caller and stackdepth tests for dtrace provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-5-eugene.loh@oracle.com> From: Eugene Loh Also, a few old tests, which tested caller and stackdepth using the dtrace provider, are now superfluous given the new, provider-named tests. The old tests were extremely lenient -- e.g., simply checking that these built-in variables were not -1, even though both variables are unsigned anyhow! Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- test/unittest/builtinvar/tst.caller.d | 25 ------------------- .../variables/bvar/tst.caller-dtrace.d | 20 +++++++++++++++ .../variables/bvar/tst.caller-dtrace.r | 1 + test/unittest/variables/bvar/tst.caller.d | 23 ----------------- .../variables/bvar/tst.stackdepth-dtrace.d | 23 +++++++++++++++++ .../variables/bvar/tst.stackdepth-dtrace.r | 5 ++++ test/unittest/variables/bvar/tst.stackdepth.d | 23 ----------------- 7 files changed, 49 insertions(+), 71 deletions(-) delete mode 100644 test/unittest/builtinvar/tst.caller.d create mode 100644 test/unittest/variables/bvar/tst.caller-dtrace.d create mode 100644 test/unittest/variables/bvar/tst.caller-dtrace.r delete mode 100644 test/unittest/variables/bvar/tst.caller.d create mode 100644 test/unittest/variables/bvar/tst.stackdepth-dtrace.d create mode 100644 test/unittest/variables/bvar/tst.stackdepth-dtrace.r delete mode 100644 test/unittest/variables/bvar/tst.stackdepth.d diff --git a/test/unittest/builtinvar/tst.caller.d b/test/unittest/builtinvar/tst.caller.d deleted file mode 100644 index 19a4bab9e..000000000 --- a/test/unittest/builtinvar/tst.caller.d +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Oracle Linux DTrace. - * Copyright (c) 2006, 2021, 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: print 'caller' and make sure it succeeds. - * - * SECTION: Variables/Built-in Variables - */ - -#pragma D option quiet - -BEGIN -{ - printf("The caller is %u\n", caller); - exit(0); -} - -ERROR -{ - exit(1); -} diff --git a/test/unittest/variables/bvar/tst.caller-dtrace.d b/test/unittest/variables/bvar/tst.caller-dtrace.d new file mode 100644 index 000000000..d726f38ac --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-dtrace.d @@ -0,0 +1,20 @@ +/* + * 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. + */ +/* Check 'caller'. */ + +#pragma D option quiet + +BEGIN { + trace(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.caller-dtrace.r b/test/unittest/variables/bvar/tst.caller-dtrace.r new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-dtrace.r @@ -0,0 +1 @@ +0 diff --git a/test/unittest/variables/bvar/tst.caller.d b/test/unittest/variables/bvar/tst.caller.d deleted file mode 100644 index 3d64fa98c..000000000 --- a/test/unittest/variables/bvar/tst.caller.d +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Oracle Linux DTrace. - * Copyright (c) 2020, 2021, 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 'caller' variable can be accessed and is not -1. - * - * SECTION: Variables/Built-in Variables/caller - */ - -#pragma D option quiet - -BEGIN { - trace(caller); - exit(caller != -1 ? 0 : 1); -} - -ERROR { - exit(1); -} diff --git a/test/unittest/variables/bvar/tst.stackdepth-dtrace.d b/test/unittest/variables/bvar/tst.stackdepth-dtrace.d new file mode 100644 index 000000000..1026006eb --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-dtrace.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. + */ +/* Check 'stackdepth'. */ + +#pragma D option quiet + +BEGIN { + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.stackdepth-dtrace.r b/test/unittest/variables/bvar/tst.stackdepth-dtrace.r new file mode 100644 index 000000000..1afb1f057 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-dtrace.r @@ -0,0 +1,5 @@ +DEPTH 0 +TRACE BEGIN + +TRACE END + diff --git a/test/unittest/variables/bvar/tst.stackdepth.d b/test/unittest/variables/bvar/tst.stackdepth.d deleted file mode 100644 index ad728fd85..000000000 --- a/test/unittest/variables/bvar/tst.stackdepth.d +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Oracle Linux DTrace. - * Copyright (c) 2020, 2021, 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 'stackdepth' variable can be accessed and is not -1. - * - * SECTION: Variables/Built-in Variables/stackdepth - */ - -#pragma D option quiet - -BEGIN { - trace(stackdepth); - exit(stackdepth != -1 ? 0 : 1); -} - -ERROR { - exit(1); -} -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:20:54 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:20:54 -0400 Subject: [DTrace-devel] [PATCH v2 01/14] Fix stack-skip counts for caller and stackdepth Message-ID: <20250625042107.13571-1-eugene.loh@oracle.com> From: Eugene Loh Apparently, when we call the BPF get_stack() helper function, it generally knows how many frames to skip to get the real kernel stack. For fentry/fexit, however, this is apparently not the case, and commit bc65cb44d ("cg: allow providers to specify a skip count for stack retrieval") added the ability to skip frames for fentry/fexit probes. When this "skip" is needed, however, it must must be even deeper when we descend further frames, such as when we call dt_bpf_*() precompiled functions. Add this support for dt_bpf_caller() and dt_bpf_stackdepth(). That is, if there are stack-skip frames, skip yet one more frame when inside a bpf/get_bvar.c function. Note that we declare the skip count volatile. The compiler might optimize code that uses the STACK_SKIP value, but we will subsequently perform relocations that adjust this value. Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- bpf/get_bvar.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c index 9625e764e..99a6503d5 100644 --- a/bpf/get_bvar.c +++ b/bpf/get_bvar.c @@ -53,12 +53,17 @@ noinline uint64_t dt_bvar_args(const dt_dctx_t *dctx, uint32_t idx) noinline uint64_t dt_bvar_caller(const dt_dctx_t *dctx) { - uint64_t buf[2] = { 0, }; + uint64_t buf[3] = { 0, }; + volatile uint64_t + skip = (uint64_t)(&STACK_SKIP); if (bpf_get_stack(dctx->ctx, buf, sizeof(buf), - (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK) < 0) + skip & BPF_F_SKIP_FIELD_MASK) < 0) return 0; + /* If we had to skip any frames, account for the dt_bvar_caller() frame. */ + if (skip) + return buf[2]; return buf[1]; } @@ -203,9 +208,11 @@ 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; + volatile uint64_t + skip = (uint64_t)(&STACK_SKIP); retv = bpf_get_stack(dctx->ctx, buf, bufsiz, - (uint64_t)(&STACK_SKIP) & BPF_F_SKIP_FIELD_MASK); + skip & BPF_F_SKIP_FIELD_MASK); if (retv < 0) return error(dctx, DTRACEFLT_BADSTACK, 0 /* FIXME */); @@ -217,7 +224,11 @@ noinline uint64_t dt_bvar_stackdepth(const dt_dctx_t *dctx) * 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. + * + * If we had to skip any frames, account for the dt_bvar_stackdepth() frame. */ + if (skip) + return retv / sizeof(uint64_t) - 1; return retv / sizeof(uint64_t); } -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:20:59 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:20:59 -0400 Subject: [DTrace-devel] [PATCH v2 06/14] test: caller and stackdepth tests for rawtp provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-6-eugene.loh@oracle.com> From: Eugene Loh Also, add skip_rawtp_old.x, to skip rawtp testing on older kernels for the reasons described in the file. Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- test/unittest/variables/bvar/skip_rawtp_old.x | 31 +++++++++++++++++++ .../variables/bvar/tst.caller-rawtp.d | 25 +++++++++++++++ .../variables/bvar/tst.caller-rawtp.r | 1 + .../variables/bvar/tst.caller-rawtp.r.p | 1 + .../variables/bvar/tst.caller-rawtp.x | 1 + .../variables/bvar/tst.stackdepth-rawtp.d | 27 ++++++++++++++++ .../variables/bvar/tst.stackdepth-rawtp.r | 1 + .../variables/bvar/tst.stackdepth-rawtp.r.p | 1 + .../variables/bvar/tst.stackdepth-rawtp.x | 1 + 9 files changed, 89 insertions(+) create mode 100755 test/unittest/variables/bvar/skip_rawtp_old.x create mode 100644 test/unittest/variables/bvar/tst.caller-rawtp.d create mode 100644 test/unittest/variables/bvar/tst.caller-rawtp.r create mode 120000 test/unittest/variables/bvar/tst.caller-rawtp.r.p create mode 120000 test/unittest/variables/bvar/tst.caller-rawtp.x create mode 100644 test/unittest/variables/bvar/tst.stackdepth-rawtp.d create mode 100644 test/unittest/variables/bvar/tst.stackdepth-rawtp.r create mode 120000 test/unittest/variables/bvar/tst.stackdepth-rawtp.r.p create mode 120000 test/unittest/variables/bvar/tst.stackdepth-rawtp.x diff --git a/test/unittest/variables/bvar/skip_rawtp_old.x b/test/unittest/variables/bvar/skip_rawtp_old.x new file mode 100755 index 000000000..bf7970832 --- /dev/null +++ b/test/unittest/variables/bvar/skip_rawtp_old.x @@ -0,0 +1,31 @@ +#!/bin/bash + +# +# In older kernels (e.g., UEK6), the BPF helper function had a bug with +# skipping stack frames. While that many stack frames were correctly +# skipped on the leaf end of the stack, that many frames were also +# incorrectly skipped at the root end of the output buffer. +# +# Only two DTrace providers ask for a nonzero skip count. One is the +# fentry/fexit implementation of fbt, but it was not used on such older +# kernels. +# +# The other is rawtp. Therefore, rawtp stack(), caller, and stackdepth +# results on such older kernels can be incorrect. +# +# A few other providers also have some or most probes implemented in +# terms of rawtp probes. They could have similar problems, depending +# on which probes are used. +# + +read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '` + +if [ $MAJOR -gt 5 ]; then + exit 0 +fi +if [ $MAJOR -eq 5 -a $MINOR -ge 10 ]; then + exit 0 +fi + +echo "rawtp caller, stack(), and stackdepth problematic in old kernels" +exit 2 diff --git a/test/unittest/variables/bvar/tst.caller-rawtp.d b/test/unittest/variables/bvar/tst.caller-rawtp.d new file mode 100644 index 000000000..9bc91b67a --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-rawtp.d @@ -0,0 +1,25 @@ +/* + * 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: periodic_output + */ +/* Check that 'caller' is consistent with stack(). */ + +#pragma D option quiet + +rawtp:sched:: +{ + stack(2); + sym(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.caller-rawtp.r b/test/unittest/variables/bvar/tst.caller-rawtp.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-rawtp.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/variables/bvar/tst.caller-rawtp.r.p b/test/unittest/variables/bvar/tst.caller-rawtp.r.p new file mode 120000 index 000000000..954ca96aa --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-rawtp.r.p @@ -0,0 +1 @@ +check_caller_to_stack2.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.caller-rawtp.x b/test/unittest/variables/bvar/tst.caller-rawtp.x new file mode 120000 index 000000000..37b3ef9f8 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-rawtp.x @@ -0,0 +1 @@ +skip_rawtp_old.x \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-rawtp.d b/test/unittest/variables/bvar/tst.stackdepth-rawtp.d new file mode 100644 index 000000000..b99ada9a3 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-rawtp.d @@ -0,0 +1,27 @@ +/* + * 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: periodic_output + */ +/* Check that 'stackdepth' is consistent with stack(). */ + +#pragma D option quiet + +rawtp:sched:: +{ + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(100); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.stackdepth-rawtp.r b/test/unittest/variables/bvar/tst.stackdepth-rawtp.r new file mode 100644 index 000000000..3bd29b8ed --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-rawtp.r @@ -0,0 +1 @@ +Stack depth OK diff --git a/test/unittest/variables/bvar/tst.stackdepth-rawtp.r.p b/test/unittest/variables/bvar/tst.stackdepth-rawtp.r.p new file mode 120000 index 000000000..e50f12822 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-rawtp.r.p @@ -0,0 +1 @@ +check_stackdepth_to_stack.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-rawtp.x b/test/unittest/variables/bvar/tst.stackdepth-rawtp.x new file mode 120000 index 000000000..37b3ef9f8 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-rawtp.x @@ -0,0 +1 @@ +skip_rawtp_old.x \ No newline at end of file -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:21:00 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:21:00 -0400 Subject: [DTrace-devel] [PATCH v2 07/14] test: caller and stackdepth tests for cpc provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-7-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- test/unittest/variables/bvar/tst.caller-cpc.d | 23 +++++++++++++++++ test/unittest/variables/bvar/tst.caller-cpc.r | 1 + .../variables/bvar/tst.caller-cpc.r.p | 1 + .../variables/bvar/tst.stackdepth-cpc.d | 25 +++++++++++++++++++ .../variables/bvar/tst.stackdepth-cpc.r | 1 + .../variables/bvar/tst.stackdepth-cpc.r.p | 1 + 6 files changed, 52 insertions(+) create mode 100644 test/unittest/variables/bvar/tst.caller-cpc.d create mode 100644 test/unittest/variables/bvar/tst.caller-cpc.r create mode 120000 test/unittest/variables/bvar/tst.caller-cpc.r.p create mode 100644 test/unittest/variables/bvar/tst.stackdepth-cpc.d create mode 100644 test/unittest/variables/bvar/tst.stackdepth-cpc.r create mode 120000 test/unittest/variables/bvar/tst.stackdepth-cpc.r.p diff --git a/test/unittest/variables/bvar/tst.caller-cpc.d b/test/unittest/variables/bvar/tst.caller-cpc.d new file mode 100644 index 000000000..ff275e8ad --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-cpc.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. + */ +/* Check that 'caller' is consistent with stack(). */ + +#pragma D option quiet + +cpc:::cpu_clock-all-100000000 +/stackdepth > 1/ +{ + stack(2); + sym(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.caller-cpc.r b/test/unittest/variables/bvar/tst.caller-cpc.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-cpc.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/variables/bvar/tst.caller-cpc.r.p b/test/unittest/variables/bvar/tst.caller-cpc.r.p new file mode 120000 index 000000000..954ca96aa --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-cpc.r.p @@ -0,0 +1 @@ +check_caller_to_stack2.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-cpc.d b/test/unittest/variables/bvar/tst.stackdepth-cpc.d new file mode 100644 index 000000000..5adae23a7 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-cpc.d @@ -0,0 +1,25 @@ +/* + * 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. + */ +/* Check that 'stackdepth' is consistent with stack(). */ + +#pragma D option quiet + +cpc:::cpu_clock-all-100000000 +/stackdepth > 1/ +{ + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(100); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.stackdepth-cpc.r b/test/unittest/variables/bvar/tst.stackdepth-cpc.r new file mode 100644 index 000000000..3bd29b8ed --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-cpc.r @@ -0,0 +1 @@ +Stack depth OK diff --git a/test/unittest/variables/bvar/tst.stackdepth-cpc.r.p b/test/unittest/variables/bvar/tst.stackdepth-cpc.r.p new file mode 120000 index 000000000..e50f12822 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-cpc.r.p @@ -0,0 +1 @@ +check_stackdepth_to_stack.awk \ No newline at end of file -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:20:55 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:20:55 -0400 Subject: [DTrace-devel] [PATCH v2 02/14] Add stack-skip frame count for rawtp provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-2-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- libdtrace/dt_prov_rawtp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libdtrace/dt_prov_rawtp.c b/libdtrace/dt_prov_rawtp.c index f1d3b6bc4..a36bb51f4 100644 --- a/libdtrace/dt_prov_rawtp.c +++ b/libdtrace/dt_prov_rawtp.c @@ -296,6 +296,7 @@ use_alt: dt_provimpl_t dt_rawtp = { .name = prvname, .prog_type = BPF_PROG_TYPE_RAW_TRACEPOINT, + .stack_skip = 4, .populate = &populate, .load_prog = &dt_bpf_prog_load, .trampoline = &trampoline, -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:21:01 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:21:01 -0400 Subject: [DTrace-devel] [PATCH v2 08/14] test: caller and stackdepth tests for ip provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-8-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- test/unittest/variables/bvar/tst.caller-ip.d | 22 ++++++++++++++++ test/unittest/variables/bvar/tst.caller-ip.r | 1 + .../unittest/variables/bvar/tst.caller-ip.r.p | 1 + test/unittest/variables/bvar/tst.caller-ip.t | 6 +++++ .../variables/bvar/tst.stackdepth-ip.d | 25 +++++++++++++++++++ .../variables/bvar/tst.stackdepth-ip.r | 1 + .../variables/bvar/tst.stackdepth-ip.r.p | 1 + .../variables/bvar/tst.stackdepth-ip.t | 6 +++++ 8 files changed, 63 insertions(+) create mode 100644 test/unittest/variables/bvar/tst.caller-ip.d create mode 100644 test/unittest/variables/bvar/tst.caller-ip.r create mode 120000 test/unittest/variables/bvar/tst.caller-ip.r.p create mode 100755 test/unittest/variables/bvar/tst.caller-ip.t create mode 100644 test/unittest/variables/bvar/tst.stackdepth-ip.d create mode 100644 test/unittest/variables/bvar/tst.stackdepth-ip.r create mode 120000 test/unittest/variables/bvar/tst.stackdepth-ip.r.p create mode 100755 test/unittest/variables/bvar/tst.stackdepth-ip.t diff --git a/test/unittest/variables/bvar/tst.caller-ip.d b/test/unittest/variables/bvar/tst.caller-ip.d new file mode 100644 index 000000000..05ca5c671 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-ip.d @@ -0,0 +1,22 @@ +/* + * 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. + */ +/* Check that 'caller' is consistent with stack(). */ + +#pragma D option quiet + +ip::: +{ + stack(2); + sym(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.caller-ip.r b/test/unittest/variables/bvar/tst.caller-ip.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-ip.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/variables/bvar/tst.caller-ip.r.p b/test/unittest/variables/bvar/tst.caller-ip.r.p new file mode 120000 index 000000000..954ca96aa --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-ip.r.p @@ -0,0 +1 @@ +check_caller_to_stack2.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.caller-ip.t b/test/unittest/variables/bvar/tst.caller-ip.t new file mode 100755 index 000000000..1ce076b86 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-ip.t @@ -0,0 +1,6 @@ +#!/bin/sh + +testdir="$(dirname $_test)" +local=127.0.0.1 + +$testdir/../../ip/perlping.pl icmp $local diff --git a/test/unittest/variables/bvar/tst.stackdepth-ip.d b/test/unittest/variables/bvar/tst.stackdepth-ip.d new file mode 100644 index 000000000..a35d1e517 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-ip.d @@ -0,0 +1,25 @@ +/* + * 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. + */ +/* Check that 'stackdepth' is consistent with stack(). */ + +#pragma D option quiet + +ip::: +/stackdepth > 0/ +{ + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(100); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.stackdepth-ip.r b/test/unittest/variables/bvar/tst.stackdepth-ip.r new file mode 100644 index 000000000..3bd29b8ed --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-ip.r @@ -0,0 +1 @@ +Stack depth OK diff --git a/test/unittest/variables/bvar/tst.stackdepth-ip.r.p b/test/unittest/variables/bvar/tst.stackdepth-ip.r.p new file mode 120000 index 000000000..e50f12822 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-ip.r.p @@ -0,0 +1 @@ +check_stackdepth_to_stack.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-ip.t b/test/unittest/variables/bvar/tst.stackdepth-ip.t new file mode 100755 index 000000000..1ce076b86 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-ip.t @@ -0,0 +1,6 @@ +#!/bin/sh + +testdir="$(dirname $_test)" +local=127.0.0.1 + +$testdir/../../ip/perlping.pl icmp $local -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:21:02 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:21:02 -0400 Subject: [DTrace-devel] [PATCH v2 09/14] test: caller and stackdepth tests for profile provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-9-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- test/unittest/builtinvar/tst.caller1.d | 29 ------------------- .../variables/bvar/tst.caller-profile.d | 23 +++++++++++++++ .../variables/bvar/tst.caller-profile.r | 1 + .../variables/bvar/tst.caller-profile.r.p | 1 + .../variables/bvar/tst.stackdepth-profile.d | 25 ++++++++++++++++ .../variables/bvar/tst.stackdepth-profile.r | 1 + .../variables/bvar/tst.stackdepth-profile.r.p | 1 + 7 files changed, 52 insertions(+), 29 deletions(-) delete mode 100644 test/unittest/builtinvar/tst.caller1.d create mode 100644 test/unittest/variables/bvar/tst.caller-profile.d create mode 100644 test/unittest/variables/bvar/tst.caller-profile.r create mode 120000 test/unittest/variables/bvar/tst.caller-profile.r.p create mode 100644 test/unittest/variables/bvar/tst.stackdepth-profile.d create mode 100644 test/unittest/variables/bvar/tst.stackdepth-profile.r create mode 120000 test/unittest/variables/bvar/tst.stackdepth-profile.r.p diff --git a/test/unittest/builtinvar/tst.caller1.d b/test/unittest/builtinvar/tst.caller1.d deleted file mode 100644 index ca0f098f3..000000000 --- a/test/unittest/builtinvar/tst.caller1.d +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Oracle Linux DTrace. - * Copyright (c) 2006, 2021, 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: To print caller from profile and make sure it succeeds. - * - * SECTION: Variables/Built-in Variables - */ - -#pragma D option quiet - -BEGIN -{ -} - -tick-10ms -{ - printf("The caller is %u\n", caller); - exit (0); -} - -ERROR -{ - exit(1); -} diff --git a/test/unittest/variables/bvar/tst.caller-profile.d b/test/unittest/variables/bvar/tst.caller-profile.d new file mode 100644 index 000000000..82d21f784 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-profile.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. + */ +/* Check that 'caller' is consistent with stack(). */ + +#pragma D option quiet + +profile:::tick-50ms +/stackdepth > 1/ +{ + stack(2); + sym(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.caller-profile.r b/test/unittest/variables/bvar/tst.caller-profile.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-profile.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/variables/bvar/tst.caller-profile.r.p b/test/unittest/variables/bvar/tst.caller-profile.r.p new file mode 120000 index 000000000..954ca96aa --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-profile.r.p @@ -0,0 +1 @@ +check_caller_to_stack2.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-profile.d b/test/unittest/variables/bvar/tst.stackdepth-profile.d new file mode 100644 index 000000000..614c43a08 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-profile.d @@ -0,0 +1,25 @@ +/* + * 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. + */ +/* Check that 'stackdepth' is consistent with stack(). */ + +#pragma D option quiet + +profile:::tick-50ms +/stackdepth > 1/ +{ + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(100); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.stackdepth-profile.r b/test/unittest/variables/bvar/tst.stackdepth-profile.r new file mode 100644 index 000000000..3bd29b8ed --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-profile.r @@ -0,0 +1 @@ +Stack depth OK diff --git a/test/unittest/variables/bvar/tst.stackdepth-profile.r.p b/test/unittest/variables/bvar/tst.stackdepth-profile.r.p new file mode 120000 index 000000000..e50f12822 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-profile.r.p @@ -0,0 +1 @@ +check_stackdepth_to_stack.awk \ No newline at end of file -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:21:03 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:21:03 -0400 Subject: [DTrace-devel] [PATCH v2 10/14] test: caller and stackdepth tests for sched provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-10-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- .../variables/bvar/tst.caller-sched.d | 32 +++++++++++++++++ .../variables/bvar/tst.caller-sched.r | 1 + .../variables/bvar/tst.caller-sched.r.p | 1 + .../variables/bvar/tst.stackdepth-sched.d | 34 +++++++++++++++++++ .../variables/bvar/tst.stackdepth-sched.r | 1 + .../variables/bvar/tst.stackdepth-sched.r.p | 1 + 6 files changed, 70 insertions(+) create mode 100644 test/unittest/variables/bvar/tst.caller-sched.d create mode 100644 test/unittest/variables/bvar/tst.caller-sched.r create mode 120000 test/unittest/variables/bvar/tst.caller-sched.r.p create mode 100644 test/unittest/variables/bvar/tst.stackdepth-sched.d create mode 100644 test/unittest/variables/bvar/tst.stackdepth-sched.r create mode 120000 test/unittest/variables/bvar/tst.stackdepth-sched.r.p diff --git a/test/unittest/variables/bvar/tst.caller-sched.d b/test/unittest/variables/bvar/tst.caller-sched.d new file mode 100644 index 000000000..bf73608ff --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-sched.d @@ -0,0 +1,32 @@ +/* + * 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: periodic_output + */ +/* Check that 'caller' is consistent with stack(). */ + +#pragma D option quiet + + +/* + * Some probes are implemented in terms of rawtp probes. Avoid them + * due to stack-skip issues on older kernels. + */ +sched:::dequeue, +sched:::enqueue, +sched:::tick +{ + stack(2); + sym(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.caller-sched.r b/test/unittest/variables/bvar/tst.caller-sched.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-sched.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/variables/bvar/tst.caller-sched.r.p b/test/unittest/variables/bvar/tst.caller-sched.r.p new file mode 120000 index 000000000..954ca96aa --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-sched.r.p @@ -0,0 +1 @@ +check_caller_to_stack2.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-sched.d b/test/unittest/variables/bvar/tst.stackdepth-sched.d new file mode 100644 index 000000000..05be31721 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-sched.d @@ -0,0 +1,34 @@ +/* + * 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: periodic_output + */ +/* Check that 'stackdepth' is consistent with stack(). */ + +#pragma D option quiet + + +/* + * Some probes are implemented in terms of rawtp probes. Avoid them + * due to stack-skip issues on older kernels. + */ +sched:::dequeue, +sched:::enqueue, +sched:::tick +{ + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(100); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.stackdepth-sched.r b/test/unittest/variables/bvar/tst.stackdepth-sched.r new file mode 100644 index 000000000..3bd29b8ed --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-sched.r @@ -0,0 +1 @@ +Stack depth OK diff --git a/test/unittest/variables/bvar/tst.stackdepth-sched.r.p b/test/unittest/variables/bvar/tst.stackdepth-sched.r.p new file mode 120000 index 000000000..e50f12822 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-sched.r.p @@ -0,0 +1 @@ +check_stackdepth_to_stack.awk \ No newline at end of file -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:21:04 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:21:04 -0400 Subject: [DTrace-devel] [PATCH v2 11/14] test: caller and stackdepth tests for proc provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-11-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- .../unittest/variables/bvar/tst.caller-proc.d | 34 ++++++++++++++++++ .../unittest/variables/bvar/tst.caller-proc.r | 1 + .../variables/bvar/tst.caller-proc.r.p | 1 + .../variables/bvar/tst.stackdepth-proc.d | 36 +++++++++++++++++++ .../variables/bvar/tst.stackdepth-proc.r | 1 + .../variables/bvar/tst.stackdepth-proc.r.p | 1 + 6 files changed, 74 insertions(+) create mode 100644 test/unittest/variables/bvar/tst.caller-proc.d create mode 100644 test/unittest/variables/bvar/tst.caller-proc.r create mode 120000 test/unittest/variables/bvar/tst.caller-proc.r.p create mode 100644 test/unittest/variables/bvar/tst.stackdepth-proc.d create mode 100644 test/unittest/variables/bvar/tst.stackdepth-proc.r create mode 120000 test/unittest/variables/bvar/tst.stackdepth-proc.r.p diff --git a/test/unittest/variables/bvar/tst.caller-proc.d b/test/unittest/variables/bvar/tst.caller-proc.d new file mode 100644 index 000000000..7c3557e2c --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-proc.d @@ -0,0 +1,34 @@ +/* + * 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: periodic_output + */ + +#pragma D option quiet + +/* + * Some probes are implemented in terms of rawtp probes. Avoid them + * due to stack-skip issues on older kernels. + */ +proc:::exec, +proc:::exec-failure, +proc:::exec-success, +proc:::lwp-start, +proc:::signal-clear, +proc:::signal-send, +proc:::start +{ + stack(2); + sym(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.caller-proc.r b/test/unittest/variables/bvar/tst.caller-proc.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-proc.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/variables/bvar/tst.caller-proc.r.p b/test/unittest/variables/bvar/tst.caller-proc.r.p new file mode 120000 index 000000000..954ca96aa --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-proc.r.p @@ -0,0 +1 @@ +check_caller_to_stack2.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-proc.d b/test/unittest/variables/bvar/tst.stackdepth-proc.d new file mode 100644 index 000000000..75f720370 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-proc.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. + */ +/* + * @@trigger: periodic_output + */ + +#pragma D option quiet + +/* + * Some probes are implemented in terms of rawtp probes. Avoid them + * due to stack-skip issues on older kernels. + */ +proc:::exec, +proc:::exec-failure, +proc:::exec-success, +proc:::lwp-start, +proc:::signal-clear, +proc:::signal-send, +proc:::start +{ + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(100); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.stackdepth-proc.r b/test/unittest/variables/bvar/tst.stackdepth-proc.r new file mode 100644 index 000000000..3bd29b8ed --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-proc.r @@ -0,0 +1 @@ +Stack depth OK diff --git a/test/unittest/variables/bvar/tst.stackdepth-proc.r.p b/test/unittest/variables/bvar/tst.stackdepth-proc.r.p new file mode 120000 index 000000000..e50f12822 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-proc.r.p @@ -0,0 +1 @@ +check_stackdepth_to_stack.awk \ No newline at end of file -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:21:05 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:21:05 -0400 Subject: [DTrace-devel] [PATCH v2 12/14] test: caller and stackdepth tests for rawfbt provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-12-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- .../variables/bvar/tst.caller-rawfbt.d | 26 +++++++++++++++++ .../variables/bvar/tst.caller-rawfbt.r | 1 + .../variables/bvar/tst.caller-rawfbt.r.p | 1 + .../variables/bvar/tst.stackdepth-rawfbt.d | 28 +++++++++++++++++++ .../variables/bvar/tst.stackdepth-rawfbt.r | 1 + .../variables/bvar/tst.stackdepth-rawfbt.r.p | 1 + 6 files changed, 58 insertions(+) create mode 100644 test/unittest/variables/bvar/tst.caller-rawfbt.d create mode 100644 test/unittest/variables/bvar/tst.caller-rawfbt.r create mode 120000 test/unittest/variables/bvar/tst.caller-rawfbt.r.p create mode 100644 test/unittest/variables/bvar/tst.stackdepth-rawfbt.d create mode 100644 test/unittest/variables/bvar/tst.stackdepth-rawfbt.r create mode 120000 test/unittest/variables/bvar/tst.stackdepth-rawfbt.r.p diff --git a/test/unittest/variables/bvar/tst.caller-rawfbt.d b/test/unittest/variables/bvar/tst.caller-rawfbt.d new file mode 100644 index 000000000..9be644ecc --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-rawfbt.d @@ -0,0 +1,26 @@ +/* + * 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: periodic_output + */ +/* Check that 'caller' is consistent with stack(). */ + +#pragma D option quiet + +rawfbt::ksys_write:entry +/pid == $target/ +{ + stack(2); + sym(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.caller-rawfbt.r b/test/unittest/variables/bvar/tst.caller-rawfbt.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-rawfbt.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/variables/bvar/tst.caller-rawfbt.r.p b/test/unittest/variables/bvar/tst.caller-rawfbt.r.p new file mode 120000 index 000000000..954ca96aa --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-rawfbt.r.p @@ -0,0 +1 @@ +check_caller_to_stack2.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-rawfbt.d b/test/unittest/variables/bvar/tst.stackdepth-rawfbt.d new file mode 100644 index 000000000..1c0afffe8 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-rawfbt.d @@ -0,0 +1,28 @@ +/* + * 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: periodic_output + */ +/* Check that 'stackdepth' is consistent with stack(). */ + +#pragma D option quiet + +rawfbt::ksys_write:entry +/pid == $target/ +{ + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(100); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.stackdepth-rawfbt.r b/test/unittest/variables/bvar/tst.stackdepth-rawfbt.r new file mode 100644 index 000000000..3bd29b8ed --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-rawfbt.r @@ -0,0 +1 @@ +Stack depth OK diff --git a/test/unittest/variables/bvar/tst.stackdepth-rawfbt.r.p b/test/unittest/variables/bvar/tst.stackdepth-rawfbt.r.p new file mode 120000 index 000000000..e50f12822 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-rawfbt.r.p @@ -0,0 +1 @@ +check_stackdepth_to_stack.awk \ No newline at end of file -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:21:07 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:21:07 -0400 Subject: [DTrace-devel] [PATCH v2 14/14] test: caller and stackdepth tests for lockstat provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-14-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- .../variables/bvar/skip_lockstat_5.10.x | 13 ++++++++++ .../variables/bvar/tst.caller-lockstat.d | 23 +++++++++++++++++ .../variables/bvar/tst.caller-lockstat.r | 1 + .../variables/bvar/tst.caller-lockstat.r.p | 1 + .../variables/bvar/tst.caller-lockstat.t | 3 +++ .../variables/bvar/tst.caller-lockstat.x | 1 + .../variables/bvar/tst.stackdepth-lockstat.d | 25 +++++++++++++++++++ .../variables/bvar/tst.stackdepth-lockstat.r | 1 + .../bvar/tst.stackdepth-lockstat.r.p | 1 + .../variables/bvar/tst.stackdepth-lockstat.t | 3 +++ .../variables/bvar/tst.stackdepth-lockstat.x | 1 + 11 files changed, 73 insertions(+) create mode 100755 test/unittest/variables/bvar/skip_lockstat_5.10.x create mode 100644 test/unittest/variables/bvar/tst.caller-lockstat.d create mode 100644 test/unittest/variables/bvar/tst.caller-lockstat.r create mode 120000 test/unittest/variables/bvar/tst.caller-lockstat.r.p create mode 100755 test/unittest/variables/bvar/tst.caller-lockstat.t create mode 120000 test/unittest/variables/bvar/tst.caller-lockstat.x create mode 100644 test/unittest/variables/bvar/tst.stackdepth-lockstat.d create mode 100644 test/unittest/variables/bvar/tst.stackdepth-lockstat.r create mode 120000 test/unittest/variables/bvar/tst.stackdepth-lockstat.r.p create mode 100755 test/unittest/variables/bvar/tst.stackdepth-lockstat.t create mode 120000 test/unittest/variables/bvar/tst.stackdepth-lockstat.x diff --git a/test/unittest/variables/bvar/skip_lockstat_5.10.x b/test/unittest/variables/bvar/skip_lockstat_5.10.x new file mode 100755 index 000000000..146443fd2 --- /dev/null +++ b/test/unittest/variables/bvar/skip_lockstat_5.10.x @@ -0,0 +1,13 @@ +#!/bin/bash + +read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '` + +if [ $MAJOR -gt 5 ]; then + exit 0 +fi +if [ $MAJOR -eq 5 -a $MINOR -ge 10 ]; then + exit 0 +fi + +echo "lockstat disabled prior to 5.10" +exit 1 diff --git a/test/unittest/variables/bvar/tst.caller-lockstat.d b/test/unittest/variables/bvar/tst.caller-lockstat.d new file mode 100644 index 000000000..fbd1f1ae0 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-lockstat.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. + */ +/* Check that 'caller' is consistent with stack(). */ + +#pragma D option quiet + +lockstat:::*acquire +/pid == $target/ +{ + stack(2); + sym(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.caller-lockstat.r b/test/unittest/variables/bvar/tst.caller-lockstat.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-lockstat.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/variables/bvar/tst.caller-lockstat.r.p b/test/unittest/variables/bvar/tst.caller-lockstat.r.p new file mode 120000 index 000000000..954ca96aa --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-lockstat.r.p @@ -0,0 +1 @@ +check_caller_to_stack2.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.caller-lockstat.t b/test/unittest/variables/bvar/tst.caller-lockstat.t new file mode 100755 index 000000000..fec0d2715 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-lockstat.t @@ -0,0 +1,3 @@ +#!/bin/sh + +sleep 10s diff --git a/test/unittest/variables/bvar/tst.caller-lockstat.x b/test/unittest/variables/bvar/tst.caller-lockstat.x new file mode 120000 index 000000000..539f14255 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-lockstat.x @@ -0,0 +1 @@ +skip_lockstat_5.10.x \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-lockstat.d b/test/unittest/variables/bvar/tst.stackdepth-lockstat.d new file mode 100644 index 000000000..de2b33dd4 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-lockstat.d @@ -0,0 +1,25 @@ +/* + * 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. + */ +/* Check that 'stackdepth' is consistent with stack(). */ + +#pragma D option quiet + +lockstat:::*acquire +/pid == $target/ +{ + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(100); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +} diff --git a/test/unittest/variables/bvar/tst.stackdepth-lockstat.r b/test/unittest/variables/bvar/tst.stackdepth-lockstat.r new file mode 100644 index 000000000..3bd29b8ed --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-lockstat.r @@ -0,0 +1 @@ +Stack depth OK diff --git a/test/unittest/variables/bvar/tst.stackdepth-lockstat.r.p b/test/unittest/variables/bvar/tst.stackdepth-lockstat.r.p new file mode 120000 index 000000000..e50f12822 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-lockstat.r.p @@ -0,0 +1 @@ +check_stackdepth_to_stack.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-lockstat.t b/test/unittest/variables/bvar/tst.stackdepth-lockstat.t new file mode 100755 index 000000000..fec0d2715 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-lockstat.t @@ -0,0 +1,3 @@ +#!/bin/sh + +sleep 10s diff --git a/test/unittest/variables/bvar/tst.stackdepth-lockstat.x b/test/unittest/variables/bvar/tst.stackdepth-lockstat.x new file mode 120000 index 000000000..539f14255 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-lockstat.x @@ -0,0 +1 @@ +skip_lockstat_5.10.x \ No newline at end of file -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 04:21:06 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 00:21:06 -0400 Subject: [DTrace-devel] [PATCH v2 13/14] test: caller and stackdepth tests for io provider In-Reply-To: <20250625042107.13571-1-eugene.loh@oracle.com> References: <20250625042107.13571-1-eugene.loh@oracle.com> Message-ID: <20250625042107.13571-13-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock --- test/unittest/variables/bvar/tst.caller-io.r | 1 + .../unittest/variables/bvar/tst.caller-io.r.p | 1 + test/unittest/variables/bvar/tst.caller-io.sh | 39 ++++++++++++++++++ test/unittest/variables/bvar/tst.caller-io.x | 1 + .../variables/bvar/tst.stackdepth-io.r | 1 + .../variables/bvar/tst.stackdepth-io.r.p | 1 + .../variables/bvar/tst.stackdepth-io.sh | 41 +++++++++++++++++++ .../variables/bvar/tst.stackdepth-io.x | 1 + 8 files changed, 86 insertions(+) create mode 100644 test/unittest/variables/bvar/tst.caller-io.r create mode 120000 test/unittest/variables/bvar/tst.caller-io.r.p create mode 100755 test/unittest/variables/bvar/tst.caller-io.sh create mode 120000 test/unittest/variables/bvar/tst.caller-io.x create mode 100644 test/unittest/variables/bvar/tst.stackdepth-io.r create mode 120000 test/unittest/variables/bvar/tst.stackdepth-io.r.p create mode 100755 test/unittest/variables/bvar/tst.stackdepth-io.sh create mode 120000 test/unittest/variables/bvar/tst.stackdepth-io.x diff --git a/test/unittest/variables/bvar/tst.caller-io.r b/test/unittest/variables/bvar/tst.caller-io.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-io.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/variables/bvar/tst.caller-io.r.p b/test/unittest/variables/bvar/tst.caller-io.r.p new file mode 120000 index 000000000..954ca96aa --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-io.r.p @@ -0,0 +1 @@ +check_caller_to_stack2.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.caller-io.sh b/test/unittest/variables/bvar/tst.caller-io.sh new file mode 100755 index 000000000..957406da4 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-io.sh @@ -0,0 +1,39 @@ +#!/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. + +# Check that 'caller' is consistent with stack(). + +dtrace=$1 +nblocks=1024 +filesize=$((1024*$nblocks)) +fsoptions="defaults,atime,diratime,nosuid,nodev" +iodir=$tmpdir/tst-caller-io.$$ +tempfile=`mktemp -u -p $iodir` + +trap "umount $iodir; rmdir $iodir; rm -f $iodir.img" QUIT EXIT + +# create loopback file system +dd if=/dev/zero of=$iodir.img bs=1024 count=$((300*$nblocks)) status=none +mkfs.xfs $iodir.img > /dev/null +mkdir $iodir +test/triggers/io-mount-local.sh $iodir xfs $fsoptions + +$dtrace $dt_flags -c "test/triggers/doio.sh $tempfile $filesize test/triggers/io-mount-local.sh $iodir xfs $fsoptions" -qn ' +io::: +{ + stack(2); + sym(caller); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +}' + +exit $? diff --git a/test/unittest/variables/bvar/tst.caller-io.x b/test/unittest/variables/bvar/tst.caller-io.x new file mode 120000 index 000000000..37b3ef9f8 --- /dev/null +++ b/test/unittest/variables/bvar/tst.caller-io.x @@ -0,0 +1 @@ +skip_rawtp_old.x \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-io.r b/test/unittest/variables/bvar/tst.stackdepth-io.r new file mode 100644 index 000000000..3bd29b8ed --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-io.r @@ -0,0 +1 @@ +Stack depth OK diff --git a/test/unittest/variables/bvar/tst.stackdepth-io.r.p b/test/unittest/variables/bvar/tst.stackdepth-io.r.p new file mode 120000 index 000000000..e50f12822 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-io.r.p @@ -0,0 +1 @@ +check_stackdepth_to_stack.awk \ No newline at end of file diff --git a/test/unittest/variables/bvar/tst.stackdepth-io.sh b/test/unittest/variables/bvar/tst.stackdepth-io.sh new file mode 100755 index 000000000..51aeecd16 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-io.sh @@ -0,0 +1,41 @@ +#!/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. + +# Check that 'stackdepth' is consistent with stack(). + +dtrace=$1 +nblocks=1024 +filesize=$((1024*$nblocks)) +fsoptions="defaults,atime,diratime,nosuid,nodev" +iodir=$tmpdir/tst-stackdepth-io.$$ +tempfile=`mktemp -u -p $iodir` + +trap "umount $iodir; rmdir $iodir; rm -f $iodir.img" QUIT EXIT + +# create loopback file system +dd if=/dev/zero of=$iodir.img bs=1024 count=$((300*$nblocks)) status=none +mkfs.xfs $iodir.img > /dev/null +mkdir $iodir +test/triggers/io-mount-local.sh $iodir xfs $fsoptions + +$dtrace $dt_flags -c "test/triggers/doio.sh $tempfile $filesize test/triggers/io-mount-local.sh $iodir xfs $fsoptions" -qn ' +io::: +{ + printf("DEPTH %d\n", stackdepth); + printf("TRACE BEGIN\n"); + stack(100); + printf("TRACE END\n"); + exit(0); +} + +ERROR +{ + printf("error encountered\n"); + exit(1); +}' + +exit $? diff --git a/test/unittest/variables/bvar/tst.stackdepth-io.x b/test/unittest/variables/bvar/tst.stackdepth-io.x new file mode 120000 index 000000000..37b3ef9f8 --- /dev/null +++ b/test/unittest/variables/bvar/tst.stackdepth-io.x @@ -0,0 +1 @@ +skip_rawtp_old.x \ No newline at end of file -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 06:03:01 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 02:03:01 -0400 Subject: [DTrace-devel] [PATCH v2] Optimize USDT discovery a little Message-ID: <20250625060305.15707-1-eugene.loh@oracle.com> From: Eugene Loh We want to reduce the performance cost of USDT discovery if possible. Specifically, a number of statements -- with probe descriptions such as "dtrace:::BEGIN" that could never specify USDT probes -- will not get their clause flags set with DT_CLSFLAG_USDT_EXCLUDE. So these statements get considered unnecessarily during periodic probe discovery. Therefore: *) Expand ignore_clause(dtp, n, uprp) to support the case uprp==NULL. This case is independent of any knowledge of a specific underlying probe. *) During probe discovery, check ignore_clause(dtp, i, NULL). This sets the DT_CLSFLAG_USDT_[INCLUDE|EXCLUDE] flag and allows faster exclusion of statements that do not need to be reconsidered. To take advantage of this optimization, users should specify providers. E.g., instead of "BEGIN" (which could conceivably be a USDT probe), specify "dtrace:::BEGIN". Signed-off-by: Eugene Loh --- libdtrace/dt_prov_uprobe.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index cf5cfd431..5ba50b678 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -504,7 +504,8 @@ clean_usdt_probes(dtrace_hdl_t *dtp) /* * Judge whether clause "n" could ever be called as a USDT probe - * for this underlying probe. + * for this underlying probe. We can pass uprp==NULL to see if + * the clause can be excluded for every probe. */ static int ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp) @@ -512,6 +513,9 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp) dtrace_stmtdesc_t *stp = dtp->dt_stmts[n]; dtrace_probedesc_t *pdp = &stp->dtsd_ecbdesc->dted_probe; + if (stp == NULL) + return 1; + /* * Some clauses could never be called for a USDT probe, * regardless of the underlying probe uprp. Cache this @@ -525,7 +529,7 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp) * neither '*' nor a digit, it cannot be a USDT probe. */ if (len > 1) { - char lastchar = pdp->prv[len - 1]; + char lastchar = (pdp->prv[0] != '\0' ? pdp->prv[len - 1] : '*'); if (lastchar != '*' && !isdigit(lastchar)) { dt_stmt_clsflag_set(stp, DT_CLSFLAG_USDT_EXCLUDE); @@ -555,6 +559,8 @@ ignore_clause(dtrace_hdl_t *dtp, int n, const dt_probe_t *uprp) } if (dt_stmt_clsflag_test(stp, DT_CLSFLAG_USDT_EXCLUDE) == 1) return 1; + if (uprp == NULL) + return 0; /* * If we cannot ignore this statement, try to use uprp. @@ -751,13 +757,9 @@ static int discover(dtrace_hdl_t *dtp) */ memset(&pcb, 0, sizeof(dt_pcb_t)); for (i = 0; i < dtp->dt_stmt_nextid; i++) { - dtrace_stmtdesc_t *stp; - - stp = dtp->dt_stmts[i]; - if (stp == NULL) + if (ignore_clause(dtp, i, NULL)) continue; - if (dt_stmt_clsflag_test(stp, DT_CLSFLAG_USDT_EXCLUDE) != 1) - dt_pid_create_usdt_probes(&stp->dtsd_ecbdesc->dted_probe, dtp, &pcb); + dt_pid_create_usdt_probes(&dtp->dt_stmts[i]->dtsd_ecbdesc->dted_probe, dtp, &pcb); } return 0; -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 06:03:02 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 02:03:02 -0400 Subject: [DTrace-devel] [PATCH v2 3/4] Sync up the version numbers In-Reply-To: <20250625060305.15707-1-eugene.loh@oracle.com> References: <20250625060305.15707-1-eugene.loh@oracle.com> Message-ID: <20250625060305.15707-2-eugene.loh@oracle.com> From: Eugene Loh DTrace has many version numbers -- e.g., for the release, packaging, and API. In reality, the variations in numbering have become nearly meaningless: - Packaging numbers -- like the Version in the dtrace*spec RPM spec file and the VERSION in GNUmakefile -- have basically been tracking the DTrace release since 2.0 anyway. - Stability attributes for idents are haphazard. Generally, they are 1.0 (or sometimes other 1.x), and all the BPFs are 2.0. While this is generally accurate, it is not exactly robust, and idents are sometimes introduced or modified without careful regard to the version number. Further, the stability of user D scripts is likely to depend more on kernel variations -- e.g., the contents of available_filter_functions -- than on D changes. - Version number updates are susceptible to mistakes, and so there have been version mismatches. Bring the version numbers into sync for 2.0.3. Clean up the descriptions in dt_version.h. Signed-off-by: Eugene Loh --- GNUmakefile | 5 +- dtrace.spec | 1 + libdtrace/dt_open.c | 4 ++ libdtrace/dt_version.h | 54 ++++++++++++-------- test/unittest/dtrace-util/tst.APIVersion.r | 2 +- test/unittest/dtrace-util/tst.APIVersion.r.p | 6 +++ test/unittest/options/tst.version.r | 2 +- test/unittest/options/tst.version.sh | 4 +- 8 files changed, 52 insertions(+), 26 deletions(-) create mode 100755 test/unittest/dtrace-util/tst.APIVersion.r.p diff --git a/GNUmakefile b/GNUmakefile index d1e18bb1b..00269785b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -3,7 +3,7 @@ # Build files in subdirectories are included by this file. # # Oracle Linux DTrace. -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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. @@ -14,7 +14,8 @@ SHELL = /bin/bash PROJECT := dtrace -VERSION := 2.0.1 +# When updating version, see comments in dt_version.h. +VERSION := 2.0.3 # Verify supported hardware. diff --git a/dtrace.spec b/dtrace.spec index 6bb792acb..dd44a5b67 100644 --- a/dtrace.spec +++ b/dtrace.spec @@ -72,6 +72,7 @@ Requires: libdtrace-ctf >= 1.1.0 BuildRequires: libdtrace-ctf-devel >= 1.1.0 %endif Summary: DTrace user interface. +# When updating version, see comments in dt_version.h. Version: 2.0.3 Release: 1%{?dist} Source: dtrace-%{version}.tar.bz2 diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c index 7d47cab34..6cb797df6 100644 --- a/libdtrace/dt_open.c +++ b/libdtrace/dt_open.c @@ -60,6 +60,10 @@ const dt_version_t _dtrace_versions[] = { DT_VERS_1_6_3, /* D API 1.6.3 */ DT_VERS_1_6_4, /* D API 1.6.4 */ DT_VERS_2_0, /* D API 2.0 */ + DT_VERS_2_0_1, /* D API 2.0.1 */ + DT_VERS_2_0_2, /* D API 2.0.2 */ + DT_VERS_2_0_3, /* D API 2.0.3 */ + /* When updating version, see comments in dt_version.h. */ 0 }; diff --git a/libdtrace/dt_version.h b/libdtrace/dt_version.h index 0f47ea70d..5cfcab69a 100644 --- a/libdtrace/dt_version.h +++ b/libdtrace/dt_version.h @@ -37,32 +37,28 @@ extern "C" { * * These #defines are used in identifier tables to fill in the version fields * associated with each identifier. The DT_VERS_* macros declare the encoded - * integer values of all versions used so far. DT_VERS_STRING must be an ASCII - * string that contains the latest version within it along with any suffixes - * (e.g. Beta). You must update DT_VERS_STRING when adding a new version, - * and then add the new version to the _dtrace_versions[] array declared in - * dt_open.c. + * integer values of all versions used so far. * - * Refer to the Solaris Dynamic Tracing Guide Versioning chapter for an - * explanation of these DTrace features and their values. + * The major number should be incremented when a fundamental change has been + * made that would affect all consumers, and would reflect sweeping changes + * to DTrace or the D language. + * + * The minor number should be incremented when a change is introduced that + * could break scripts that had previously worked; for example, adding a + * new built-in variable could break a script which was already using that + * identifier. + * + * The micro number should be changed when introducing functionality changes + * or major bug fixes that do not affect backward compatibility -- this is + * merely to make capabilities easily determined from the version number. + * + * Minor bugs do not require any modification to the version number. * * NOTE: Although the DTrace versioning scheme supports the labeling and * introduction of incompatible changes (e.g. dropping an interface in a * major release), the libdtrace code does not currently support this. * All versions are assumed to strictly inherit from one another. If * we ever need to provide divergent interfaces, this will need work. - * - * The version number should be increased for every customer visible release - * of Solaris. The major number should be incremented when a fundamental - * change has been made that would affect all consumers, and would reflect - * sweeping changes to DTrace or the D language. The minor number should be - * incremented when a change is introduced that could break scripts that had - * previously worked; for example, adding a new built-in variable could break - * a script which was already using that identifier. The micro number should - * be changed when introducing functionality changes or major bug fixes that - * do not affect backward compatibility -- this is merely to make capabilities - * easily determined from the version number. Minor bugs do not require any - * modification to the version number. */ #define DT_VERS_1_0 DT_VERSION_NUMBER(1, 0, 0) #define DT_VERS_1_1 DT_VERSION_NUMBER(1, 1, 0) @@ -80,8 +76,26 @@ extern "C" { #define DT_VERS_1_6_4 DT_VERSION_NUMBER(1, 6, 4) #define DT_VERS_2_0 DT_VERSION_NUMBER(2, 0, 0) #define DT_VERS_2_0_1 DT_VERSION_NUMBER(2, 0, 1) +#define DT_VERS_2_0_2 DT_VERSION_NUMBER(2, 0, 2) +#define DT_VERS_2_0_3 DT_VERSION_NUMBER(2, 0, 3) + +/* + * When the version number is updated, the following must be kept in sync: + * + * libdtrace/dt_version.h DT_VERS_STRING, an ASCII string that contains + * the latest version within it along with any + * suffixes (e.g. Beta) + * + * libdtrace/dt_open.c _dtrace_versions[] + * + * dtrace.spec Version + * + * libdtrace/Build libdtrace_VERSION + * + * GNUmakefile VERSION + */ -#define DT_VERS_STRING "Oracle D 2.0" +#define DT_VERS_STRING "Oracle D 2.0.3" #ifdef __cplusplus } diff --git a/test/unittest/dtrace-util/tst.APIVersion.r b/test/unittest/dtrace-util/tst.APIVersion.r index 6bc7b9d72..02bf03150 100644 --- a/test/unittest/dtrace-util/tst.APIVersion.r +++ b/test/unittest/dtrace-util/tst.APIVersion.r @@ -1 +1 @@ -dtrace: Oracle D 2.0 +dtrace: Oracle D 2.0.x diff --git a/test/unittest/dtrace-util/tst.APIVersion.r.p b/test/unittest/dtrace-util/tst.APIVersion.r.p new file mode 100755 index 000000000..32ec94df4 --- /dev/null +++ b/test/unittest/dtrace-util/tst.APIVersion.r.p @@ -0,0 +1,6 @@ +#!/usr/bin/gawk -f + +# The test allows the version string to vary in micro number as well as +# other suffixes (like "Beta"). The .r.p and .r files still need to be +# updated for each minor number change. +{ sub("^dtrace: Oracle D 2\\.0\\..*$", "dtrace: Oracle D 2.0.x"); print } diff --git a/test/unittest/options/tst.version.r b/test/unittest/options/tst.version.r index 15010b3db..882e208ed 100644 --- a/test/unittest/options/tst.version.r +++ b/test/unittest/options/tst.version.r @@ -1,2 +1,2 @@ -version is 2.0 +version is 2.0.x diff --git a/test/unittest/options/tst.version.sh b/test/unittest/options/tst.version.sh index ffffcdd8b..684120af8 100755 --- a/test/unittest/options/tst.version.sh +++ b/test/unittest/options/tst.version.sh @@ -1,7 +1,7 @@ #!/bin/bash # # Oracle Linux DTrace. -# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 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. # @@ -9,7 +9,7 @@ dtrace=$1 myversion=`$dtrace $dt_flags -V | gawk '{ print $NF }'` -echo version is $myversion +echo version is $myversion | sed 's:2.0.[0-9]:2.0.x:' $dtrace $dt_flags -xversion=$myversion -qn 'BEGIN { exit(0) }' exit $? -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 06:03:03 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 02:03:03 -0400 Subject: [DTrace-devel] [PATCH v2 4/4] test: Add test for predefined preprocessor definitions In-Reply-To: <20250625060305.15707-1-eugene.loh@oracle.com> References: <20250625060305.15707-1-eugene.loh@oracle.com> Message-ID: <20250625060305.15707-3-eugene.loh@oracle.com> From: Eugene Loh Orabug: 28763074 Signed-off-by: Eugene Loh Reviewed-by: Kris Van Hees --- COMMANDLINE-OPTIONS | 10 +- test/unittest/preprocessor/tst.predefined.r | 1 + test/unittest/preprocessor/tst.predefined.sh | 119 +++++++++++++++++++ 3 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 test/unittest/preprocessor/tst.predefined.r create mode 100755 test/unittest/preprocessor/tst.predefined.sh diff --git a/COMMANDLINE-OPTIONS b/COMMANDLINE-OPTIONS index 40561af91..73be89b1f 100644 --- a/COMMANDLINE-OPTIONS +++ b/COMMANDLINE-OPTIONS @@ -321,12 +321,12 @@ definitions are always specified and valid in all modes: * __sparcv9 (on SPARC? systems only when 64?bit programs are compiled) * __i386 (on x86 systems only when 32?bit programs are compiled) * __amd64 (on x86 systems only when 64?bit programs are compiled) - * _`uname -s` (for example, __Linux) + * __`uname -s` (for example, __Linux) * __SUNW_D=1 - * _SUNW_D_VERSION=0x_MMmmmuuu (where MM is the Major release value - in hexadecimal, mmm is the Minor release value in hexadecimal, - and uuu is the Micro release value in hexadecimal; see Chapter - 41, Versioning for more information about DTrace versioning) + * _SUNW_D_VERSION=(MM << 24 | mmm << 12 | uuu), where + MM is the Major release value + mmm is the Minor release value + uuu is the Micro release value -Z Permit probe descriptions that match zero probes. If the -Z option is diff --git a/test/unittest/preprocessor/tst.predefined.r b/test/unittest/preprocessor/tst.predefined.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/preprocessor/tst.predefined.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/preprocessor/tst.predefined.sh b/test/unittest/preprocessor/tst.predefined.sh new file mode 100755 index 000000000..47e35d9c6 --- /dev/null +++ b/test/unittest/preprocessor/tst.predefined.sh @@ -0,0 +1,119 @@ +#!/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. +# +# Confirm preprocessor pre-definitions. + +dtrace=$1 + +DIRNAME=$tmpdir/predefined.$$.$RANDOM +mkdir -p $DIRNAME +cd $DIRNAME + +# Arg 1 is macro that we check is defined. + +function check_defined() { + # Add to script: #ifdef is okay, else is ERROR. + echo '#ifdef' $1 >> D.d + echo 'printf("'$1' okay\n");' >> D.d + echo '#else' >> D.d + echo 'printf("ERROR! missing '$1'\n");' >> D.d + echo '#endif' >> D.d + + # Add to check file: expect "okay" message. + echo $1 okay >> chk.txt +} + +# Arg 1 is macro whose value we check to be arg 2. + +function check_value() { + # Add to script: print value. + echo 'printf("'$1'=%x\n", '$1');' >> D.d + + # Add to check file: expected value. + echo $1=$2 >> chk.txt +} + +# Arg 1 is macro that we check is not defined. + +function check_undef() { + # Add to script: #ifdef is ERROR, else is okay. + echo '#ifdef' $1 >> D.d + echo 'printf("ERROR! found '$1'\n");' >> D.d + echo '#else' >> D.d + echo 'printf("missing '$1' is okay\n");' >> D.d + echo '#endif' >> D.d + + # Add to check file: expect "okay" message. + echo missing $1 is okay >> chk.txt +} + +# Construct version string (major, minor, micro). + +read MM mmm uuu <<< `$dtrace -vV | awk '/^This is DTrace / { gsub("\\\.", " "); print $(NF-2), $(NF-1), $NF }'` +vers=`printf "%x" $(($MM << 24 | $mmm << 12 | $uuu))` + +# Start setting up the D script. + +echo 'BEGIN {' > D.d + +# Check for the preprocessor definitions of COMMANDLINE-OPTIONS. + +check_defined __linux +check_defined __unix +check_defined __SVR4 +if [ `uname -m` == x86_64 ]; then +check_defined __amd64 +else +check_undef __amd64 +fi +check_defined __`uname -s` +check_value __SUNW_D 1 +check_value __SUNW_D_VERSION $vers + +# Confirm other preprocessor definitions. + +check_defined __SUNW_D_64 + +# Confirm that __GNUC__ is not present. + +check_undef __GNUC__ + +# Finish setting up the D script. + +echo 'exit(0); }' >> D.d +echo >> chk.txt + +# Run the D script. + +$dtrace $dt_flags -qCs D.d -o out.txt +if [ $? -ne 0 ]; then + echo ERROR: DTrace failed + echo "==== D.d" + cat D.d + echo "==== out.txt" + cat out.txt + exit 1 +fi + +# Check. + +if ! diff -q chk.txt out.txt; then + echo ERROR output disagrees + echo === expect === + cat chk.txt + echo === actual === + cat out.txt + echo === diff === + diff chk.txt out.txt + exit 1 +fi + +# Indicate success. + +echo success + +exit 0 -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 06:03:04 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 02:03:04 -0400 Subject: [DTrace-devel] [PATCH v2 2/2] Extend the USDT bit mask to multiple words In-Reply-To: <20250625060305.15707-1-eugene.loh@oracle.com> References: <20250625060305.15707-1-eugene.loh@oracle.com> Message-ID: <20250625060305.15707-4-eugene.loh@oracle.com> From: Eugene Loh Currently, USDT is limited to 64 probe descriptions since the underlying probe uses a 64-bit mask to decide which probes to execute. Change to a multi-word bit mask that can be extended to however many probe descriptions there are. Also, change the mask words to be 32-bit rather than 64-bit. The reason is that, commonly, there will be fewer than 32 probe descriptions. In this case, we shorten the value of the "USDT prids" BPF map from 16 bytes uint32_t prid; long long mask[1]; down to 8 bytes uint32_t prid; uint32_t mask[1]; (The second member is smaller and no longer costs extra padding.) We also add an extern int usdt_prids_map_val_extra_bytes; to denote how many extra bytes will be needed for the extended mask. This value is computed by usdt_prids_map_val_extra_bytes_init(). Currently, this function is awkwardly called in gmap_create_usdt(), just before the value is needed. Such a call to a provider-specific function is clumsy, but there are no other calls to the provider between compilation (where the number of statements is determined) and this map creation. Signed-off-by: Eugene Loh --- libdtrace/dt_bpf.c | 6 +- libdtrace/dt_bpf_maps.h | 5 +- libdtrace/dt_prov_uprobe.c | 81 ++++++++--- .../unittest/usdt/tst.manyprobedescriptions.r | 1 + .../usdt/tst.manyprobedescriptions.sh | 64 +++++++++ .../usdt/tst.manyprobedescriptions2.r | 1 + .../usdt/tst.manyprobedescriptions2.sh | 127 ++++++++++++++++++ 7 files changed, 261 insertions(+), 24 deletions(-) create mode 100644 test/unittest/usdt/tst.manyprobedescriptions.r create mode 100755 test/unittest/usdt/tst.manyprobedescriptions.sh create mode 100644 test/unittest/usdt/tst.manyprobedescriptions2.r create mode 100755 test/unittest/usdt/tst.manyprobedescriptions2.sh diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c index ddd849d0b..029d5fcdb 100644 --- a/libdtrace/dt_bpf.c +++ b/libdtrace/dt_bpf.c @@ -967,6 +967,7 @@ gmap_create_probes(dtrace_hdl_t *dtp) return 0; } +void usdt_prids_map_val_extra_bytes_init(dtrace_hdl_t *dtp); /* * Create the 'usdt_names' and 'usdt_prids' BPF maps. * @@ -992,8 +993,11 @@ gmap_create_usdt(dtrace_hdl_t *dtp) if (dtp->dt_usdt_namesmap_fd == -1) return -1; + usdt_prids_map_val_extra_bytes_init(dtp); + dtp->dt_usdt_pridsmap_fd = create_gmap(dtp, "usdt_prids", BPF_MAP_TYPE_HASH, - sizeof(usdt_prids_map_key_t), sizeof(usdt_prids_map_val_t), nusdtprobes); + sizeof(usdt_prids_map_key_t), + sizeof(usdt_prids_map_val_t) + usdt_prids_map_val_extra_bytes, nusdtprobes); if (dtp->dt_usdt_pridsmap_fd == -1) return -1; diff --git a/libdtrace/dt_bpf_maps.h b/libdtrace/dt_bpf_maps.h index 884dc3983..bdb20c9f2 100644 --- a/libdtrace/dt_bpf_maps.h +++ b/libdtrace/dt_bpf_maps.h @@ -1,6 +1,6 @@ /* * Oracle Linux DTrace. - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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. */ @@ -48,8 +48,9 @@ typedef struct usdt_prids_map_key { } usdt_prids_map_key_t; typedef struct usdt_prids_map_val { uint32_t prid; /* should be dtrace_id_t, sys/dtrace_types.h */ - long long mask; + uint32_t mask[1]; } usdt_prids_map_val_t; +extern int usdt_prids_map_val_extra_bytes; #ifdef __cplusplus } diff --git a/libdtrace/dt_prov_uprobe.c b/libdtrace/dt_prov_uprobe.c index 5ba50b678..65413cba6 100644 --- a/libdtrace/dt_prov_uprobe.c +++ b/libdtrace/dt_prov_uprobe.c @@ -303,6 +303,8 @@ typedef struct list_key { usdt_prids_map_key_t key; } list_key_t; +int usdt_prids_map_val_extra_bytes; + static const dtrace_pattr_t pattr = { { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, @@ -403,7 +405,7 @@ clean_usdt_probes(dtrace_hdl_t *dtp) int fdprids = dtp->dt_usdt_pridsmap_fd; int fdnames = dtp->dt_usdt_namesmap_fd; usdt_prids_map_key_t key, nxt; - usdt_prids_map_val_t val; + usdt_prids_map_val_t *val = alloca(sizeof(usdt_prids_map_val_t) + usdt_prids_map_val_extra_bytes); list_key_t keys_to_delete, *elem, *elem_next; dt_probe_t *prp, *prp_next; @@ -418,7 +420,7 @@ clean_usdt_probes(dtrace_hdl_t *dtp) while (dt_bpf_map_next_key(fdprids, &key, &nxt) == 0) { memcpy(&key, &nxt, sizeof(usdt_prids_map_key_t)); - if (dt_bpf_map_lookup(fdprids, &key, &val) == -1) + if (dt_bpf_map_lookup(fdprids, &key, val) == -1) return dt_set_errno(dtp, EDT_BPF); /* Check if the process is still running. */ @@ -431,7 +433,7 @@ clean_usdt_probes(dtrace_hdl_t *dtp) * we might delete the same usdt_names entry * multiple times. That's okay. */ - dt_bpf_map_delete(fdnames, &val.prid); + dt_bpf_map_delete(fdnames, &val->prid); /* * Delete the usdt_prids entry. @@ -452,7 +454,7 @@ clean_usdt_probes(dtrace_hdl_t *dtp) * FIXME. There might be another case, where the process * is still running, but some of its USDT probes are gone? * So maybe we have to check for the existence of one of - * dtrace_probedesc_t *pdp = dtp->dt_probes[val.prid]->desc; + * dtrace_probedesc_t *pdp = dtp->dt_probes[val->prid]->desc; * char *prv = ...pdp->prv minus the numerial part; * * /run/dtrace/probes/$pid/$pdp->prv/$pdp->mod/$pdp->fun/$pdp->prb @@ -589,6 +591,33 @@ static void usdt_error(dt_pcb_t *pcb, const char *fmt, ...) longjmp(pcb->pcb_jmpbuf, EDT_COMPILER); } +void usdt_prids_map_val_extra_bytes_init(dtrace_hdl_t *dtp) { + int i, n = 0, w = sizeof(((usdt_prids_map_val_t *)0)->mask[0]); + + /* Count how many statements cannot be ignored, regardless of uprp. */ + for (i = 0; i < dtp->dt_stmt_nextid; i++) { + dtrace_stmtdesc_t *stp; + + stp = dtp->dt_stmts[i]; + if (stp == NULL || ignore_clause(dtp, i, NULL)) + continue; + + n++; + } + + /* Determine how many bytes are needed for this many bits. */ + n = (n + CHAR_BIT - 1) / CHAR_BIT; + + /* Determine how many words are needed for this many bytes. */ + n = (n + w - 1) / w; + + /* Determine how many extra bytes are needed. */ + if (n > 1) + usdt_prids_map_val_extra_bytes = (n - 1) * w; + else + usdt_prids_map_val_extra_bytes = 0; +} + static int add_probe_uprobe(dtrace_hdl_t *dtp, dt_probe_t *prp) { dtrace_difo_t *dp; @@ -650,6 +679,7 @@ static int add_probe_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp) int fd = dtp->dt_usdt_namesmap_fd; pid_t pid; list_probe_t *pup; + usdt_prids_map_val_t *val; /* Add probe name elements to usdt_names map. */ p = probnam; @@ -685,11 +715,11 @@ static int add_probe_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp) } /* Add prid and bit mask to usdt_prids map. */ + val = alloca(sizeof(usdt_prids_map_val_t) + usdt_prids_map_val_extra_bytes); for (pup = prp->prv_data; pup != NULL; pup = dt_list_next(pup)) { dt_probe_t *uprp = pup->probe; - long long mask = 0, bit = 1; + uint32_t iword = 0, mask = 0, bit = 1; usdt_prids_map_key_t key; - usdt_prids_map_val_t val; dt_uprobe_t *upp = uprp->prv_data; /* @@ -707,11 +737,15 @@ static int add_probe_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp) dtrace_stmtdesc_t *stp; stp = dtp->dt_stmts[n]; - if (stp == NULL) + if (stp == NULL || ignore_clause(dtp, n, uprp)) continue; - if (ignore_clause(dtp, n, uprp)) - continue; + if (bit == 0) { + val->mask[iword] = mask; + mask = 0; + iword++; + bit = 1; + } if (dt_gmatch(prp->desc->prv, stp->dtsd_ecbdesc->dted_probe.prv) && dt_gmatch(prp->desc->mod, stp->dtsd_ecbdesc->dted_probe.mod) && @@ -726,11 +760,11 @@ static int add_probe_usdt(dtrace_hdl_t *dtp, dt_probe_t *prp) key.pid = pid; key.uprid = uprp->desc->id; - val.prid = prp->desc->id; - val.mask = mask; + val->prid = prp->desc->id; + val->mask[iword] = mask; // FIXME Check return value, but how should errors be handled? - dt_bpf_map_update(dtp->dt_usdt_pridsmap_fd, &key, &val); + dt_bpf_map_update(dtp->dt_usdt_pridsmap_fd, &key, val); } return 0; @@ -1451,7 +1485,7 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) const list_probe_t *pop; uint_t lbl_exit = pcb->pcb_exitlbl; dt_ident_t *usdt_prids = dt_dlib_get_map(dtp, "usdt_prids"); - int n; + int n, ibit, w = CHAR_BIT * sizeof(((usdt_prids_map_val_t *)0)->mask[0]); assert(usdt_prids != NULL); @@ -1538,7 +1572,8 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) */ assert(sizeof(usdt_prids_map_key_t) <= DT_STK_SLOT_SZ); emit(dlp, BPF_STORE(BPF_W, BPF_REG_FP, DT_TRAMP_SP_SLOT(0), BPF_REG_0)); - emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_FP, DT_TRAMP_SP_SLOT(0) + (int)sizeof(pid_t), uprp->desc->id)); + emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_FP, + DT_TRAMP_SP_SLOT(0) + (int)sizeof(pid_t), uprp->desc->id)); dt_cg_xsetx(dlp, usdt_prids, DT_LBL_NONE, BPF_REG_1, usdt_prids->di_id); emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_FP)); emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_TRAMP_SP_SLOT(0))); @@ -1572,8 +1607,8 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) emit(dlp, BPF_LOAD(BPF_W, BPF_REG_1, BPF_REG_0, 0)); emit(dlp, BPF_STORE(BPF_W, BPF_REG_7, DMST_PRID, BPF_REG_1)); - /* Read the bit mask from the table lookup in %r6. */ // FIXME someday, extend this past 64 bits - emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_6, BPF_REG_0, offsetof(usdt_prids_map_val_t, mask))); + /* Store the value key for reuse. */ + emit(dlp, BPF_STORE(BPF_DW, BPF_REG_FP, DT_TRAMP_SP_SLOT(0), BPF_REG_0)); /* * Apply arg mappings, if needed. @@ -1587,21 +1622,24 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) /* * Hold the bit mask in %r6 between clause calls. */ - for (n = 0; n < dtp->dt_stmt_nextid; n++) { + for (ibit = n = 0; n < dtp->dt_stmt_nextid; n++) { dtrace_stmtdesc_t *stp; dt_ident_t *idp; uint_t lbl_next; stp = dtp->dt_stmts[n]; - if (stp == NULL) - continue; - - if (ignore_clause(dtp, n, uprp)) + if (stp == NULL || ignore_clause(dtp, n, uprp)) continue; idp = stp->dtsd_clause; lbl_next = dt_irlist_label(dlp); + /* Load the next word of the bit mask into %r6. */ + if (ibit % w == 0) { + emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_0, BPF_REG_FP, DT_TRAMP_SP_SLOT(0))); + emit(dlp, BPF_LOAD(BPF_W, BPF_REG_6, BPF_REG_0, offsetof(usdt_prids_map_val_t, mask[ibit / w]))); + } + /* If the lowest %r6 bit is 0, skip over this clause. */ emit(dlp, BPF_MOV_REG(BPF_REG_1, BPF_REG_6)); emit(dlp, BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 1)); @@ -1629,6 +1667,7 @@ static int trampoline(dt_pcb_t *pcb, uint_t exitlbl) /* Right-shift %r6. */ emit(dlp, BPF_ALU64_IMM(BPF_RSH, BPF_REG_6, 1)); + ibit++; } out: diff --git a/test/unittest/usdt/tst.manyprobedescriptions.r b/test/unittest/usdt/tst.manyprobedescriptions.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/usdt/tst.manyprobedescriptions.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/usdt/tst.manyprobedescriptions.sh b/test/unittest/usdt/tst.manyprobedescriptions.sh new file mode 100755 index 000000000..92a61d5b7 --- /dev/null +++ b/test/unittest/usdt/tst.manyprobedescriptions.sh @@ -0,0 +1,64 @@ +#!/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 +TRIGGER=$PWD/test/triggers/usdt-tst-args + +DIRNAME="$tmpdir/usdt-many_probe_descriptions.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +# Construct the D scripts and output files. +# We stick 80 probe descriptions in each of 3 scripts to test +# USDT's ability to handle hundreds of probe descriptions. +for d in 0 1 2; do +for x in 00 01 02 03 04 05 06 07 08 09 \ + 10 11 12 13 14 15 16 17 18 19 \ + 20 21 22 23 24 25 26 27 28 29 \ + 30 31 32 33 34 35 36 37 38 39 \ + 40 41 42 43 44 45 46 47 48 49 \ + 50 51 52 53 54 55 56 57 58 59 \ + 60 61 62 63 64 65 66 67 68 69 \ + 70 71 72 73 74 75 76 77 78 79 \ +; do + echo 'test_prov$target:::place { printf("'$d$x'\n"); }' >> D$d.d + echo $d$x >> expect.txt +done +done +echo 'test_prov$target:::place { exit(0); }' >> D$d.d +echo >> expect.txt + +# Run DTrace. + +$dtrace $dt_flags -c $TRIGGER -q -s D0.d -s D1.d -s D2.d >& actual.txt +if [ $? -eq 0 ]; then + if diff -q expect.txt actual.txt > /dev/null; then + echo success + exit 0 + else + echo ERROR: did not get expected results + echo === expect.txt + cat expect.txt + echo === actual.txt + cat actual.txt + echo === diff + diff expect.txt actual.txt + fi +else + echo ERROR: dtrace error + echo ==== output + cat actual.txt +fi + +echo ==== script D0.d +cat D0.d +echo ==== script D1.d +cat D1.d +echo ==== script D2.d +cat D2.d + +exit 1 diff --git a/test/unittest/usdt/tst.manyprobedescriptions2.r b/test/unittest/usdt/tst.manyprobedescriptions2.r new file mode 100644 index 000000000..2e9ba477f --- /dev/null +++ b/test/unittest/usdt/tst.manyprobedescriptions2.r @@ -0,0 +1 @@ +success diff --git a/test/unittest/usdt/tst.manyprobedescriptions2.sh b/test/unittest/usdt/tst.manyprobedescriptions2.sh new file mode 100755 index 000000000..8001cec0b --- /dev/null +++ b/test/unittest/usdt/tst.manyprobedescriptions2.sh @@ -0,0 +1,127 @@ +#!/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 uses many probes and probe descriptions. Therefore, the +# number of BPF programs to load into the kernel -- dt_bpf_load_prog() +# calling prp->prov->impl->load_prog(), which is dt_bpf_prog_load() -- +# and the duration of each load are both increasing. +# @@timeout: 400 + +dtrace=$1 + +DIRNAME="$tmpdir/usdt-many_probe_descriptions2.$$.$RANDOM" +mkdir -p $DIRNAME +cd $DIRNAME + +# Set the lists. +# - The probes will be foo$x$y. +# - The probe descriptions will be foo$x* and foo*$y, for each $d. +# So if there are nx items in xlist, ny in ylist, and nd in dlist, +# - there will be roughly nx*ny probes +# - there will be roughly (nx+ny)*nd probe descriptions + +xlist="a b c d e f g h i j k l m" +ylist="n o p q r s t u v w x y z" +dlist="0 1 2 3 4 5 6 7 8" + +# Make the trigger: Preambles. + +echo "provider testprov {" > prov.d + +echo '#include "prov.h"' > main.c +echo 'int main(int argc, char **argv) {' >> main.c + +# Make the trigger: Loop over the probes. + +for x in $xlist; do +for y in $ylist; do + echo "probe foo$x$y();" >> prov.d + echo "TESTPROV_FOO$x$y();" | awk '{ print(toupper($1)) }' >> main.c +done +done + +# Make the trigger: Epilogues. + +echo "};" >> prov.d +echo "return 0; }" >> main.c + +# Build the trigger. + +$dtrace $dt_flags -h -s prov.d +if [ $? -ne 0 ]; then + echo "failed to generate header file" >&2 + cat prov.d + exit 1 +fi +$CC $test_cppflags -c main.c +if [ $? -ne 0 ]; then + echo "failed to compile test" >&2 + cat main.c + exit 1 +fi +$dtrace $dt_flags -G -64 -s prov.d main.o +if [ $? -ne 0 ]; then + echo "failed to create DOF" >&2 + exit 1 +fi +$CC $test_ldflags -o main main.o prov.o +if [ $? -ne 0 ]; then + echo "failed to link final executable" >&2 + exit 1 +fi + +# Prepare the D script, generating the probe descriptions. + +rm -f D.d +for d in $dlist; do + for x in $xlist; do + echo 'testprov$target:::foo'$x'* { printf("'$d' '$x'* %s\n", probename) }' >> D.d + done + for y in $ylist; do + echo 'testprov$target:::foo*'$y' { printf("'$d' *'$y' %s\n", probename) }' >> D.d + done +done + +# Prepare the expected output. + +for x in $xlist; do +for y in $ylist; do +for d in $dlist; do + echo $d $x'*' foo$x$y >> expect.txt + echo $d '*'$y foo$x$y >> expect.txt +done +done +done +echo >> expect.txt + +# Run DTrace. + +$dtrace $dt_flags -c ./main -qs D.d >& actual.txt +if [ $? -ne 0 ]; then + echo ERROR: dtrace error + echo "==== D script" + cat D.d + echo "==== output" + cat actual.txt + exit 1 +fi + +# Check results. + +if diff -q expect.txt actual.txt; then + echo success + exit 0 +else + echo ERROR: unexpected results + echo "==== expect" + cat expect.txt + echo "==== actual" + cat actual.txt + echo "==== diff" + diff expect.txt actual.txt + exit 1 +fi -- 2.43.5 From eugene.loh at oracle.com Wed Jun 25 06:03:05 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Wed, 25 Jun 2025 02:03:05 -0400 Subject: [DTrace-devel] [PATCH] test: Extend timeout for many-pids test In-Reply-To: <20250625060305.15707-1-eugene.loh@oracle.com> References: <20250625060305.15707-1-eugene.loh@oracle.com> Message-ID: <20250625060305.15707-5-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh --- test/unittest/pid/tst.manypids.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unittest/pid/tst.manypids.sh b/test/unittest/pid/tst.manypids.sh index 4f77564f9..38757d0e4 100755 --- a/test/unittest/pid/tst.manypids.sh +++ b/test/unittest/pid/tst.manypids.sh @@ -5,6 +5,7 @@ # Licensed under the Universal Permissive License v 1.0 as shown at # http://oss.oracle.com/licenses/upl. # +# @@timeout: 80 if [ $# != 1 ]; then echo expected one argument: '<'dtrace-path'>' -- 2.43.5 From noreply at github.com Thu Jun 26 03:26:46 2025 From: noreply at github.com (euloh) Date: Wed, 25 Jun 2025 20:26:46 -0700 Subject: [DTrace-devel] [oracle/dtrace-utils] 117c90: Fix stack-skip counts for caller and stackdepth Message-ID: Branch: refs/heads/devel Home: https://github.com/oracle/dtrace-utils Commit: 117c90ea3f353aa40c84ad9e14343d0b383a3c46 https://github.com/oracle/dtrace-utils/commit/117c90ea3f353aa40c84ad9e14343d0b383a3c46 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: M bpf/get_bvar.c Log Message: ----------- Fix stack-skip counts for caller and stackdepth Apparently, when we call the BPF get_stack() helper function, it generally knows how many frames to skip to get the real kernel stack. For fentry/fexit, however, this is apparently not the case, and commit bc65cb44d ("cg: allow providers to specify a skip count for stack retrieval") added the ability to skip frames for fentry/fexit probes. When this "skip" is needed, however, it must must be even deeper when we descend further frames, such as when we call dt_bpf_*() precompiled functions. Add this support for dt_bpf_caller() and dt_bpf_stackdepth(). That is, if there are stack-skip frames, skip yet one more frame when inside a bpf/get_bvar.c function. Note that we declare the skip count volatile. The compiler might optimize code that uses the STACK_SKIP value, but we will subsequently perform relocations that adjust this value. Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: bcef7e17f4791d16c621da4979366d25bb38e844 https://github.com/oracle/dtrace-utils/commit/bcef7e17f4791d16c621da4979366d25bb38e844 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: M libdtrace/dt_prov_rawtp.c Log Message: ----------- Add stack-skip frame count for rawtp provider Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: d1feb8af700d036ff176da965204aa2fe0fa020b https://github.com/oracle/dtrace-utils/commit/d1feb8af700d036ff176da965204aa2fe0fa020b Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: M test/unittest/sched/tst.stackdepth.d Log Message: ----------- test: remove unnecessary "unstable" tag Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: 842eabc0ef84ea3876e65894bf43401736320814 https://github.com/oracle/dtrace-utils/commit/842eabc0ef84ea3876e65894bf43401736320814 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: A test/unittest/variables/bvar/check_caller_to_stack2.awk A test/unittest/variables/bvar/check_stackdepth_to_stack.awk A test/unittest/variables/bvar/tst.caller-fbt.d A test/unittest/variables/bvar/tst.caller-fbt.r A test/unittest/variables/bvar/tst.caller-fbt.r.p R test/unittest/variables/bvar/tst.caller2.d R test/unittest/variables/bvar/tst.caller2.r R test/unittest/variables/bvar/tst.caller2.r.p A test/unittest/variables/bvar/tst.stackdepth-fbt.d A test/unittest/variables/bvar/tst.stackdepth-fbt.r A test/unittest/variables/bvar/tst.stackdepth-fbt.r.p R test/unittest/variables/bvar/tst.stackdepth2.d R test/unittest/variables/bvar/tst.stackdepth2.r R test/unittest/variables/bvar/tst.stackdepth2.r.p Log Message: ----------- test: caller and stackdepth tests for fbt provider We will introduce a set of tests for the caller and stackdepth built-in variables for a wide selection of providers. For the caller test, we will essentially call stack(2); sym(caller); and then compare the caller to the second stack frame using the new script check_caller_to_stack2.awk. For the stackdepth test, we will essentially call printf("%d\n", stackdepth); stack(); and then compare the stackdepth to the reported frames using the new script check_stackdepth_to_stack.awk. In this patch, introduce tests for the fbt provider, along with the support scripts they need. Subsequent patches will handle other providers. The old tst.caller2.d and tst.stackdepth2.d, which tested fbt, become obsolete. Remove them. Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: 4d44babf4a36c47496c4e77d701a302ef19a8923 https://github.com/oracle/dtrace-utils/commit/4d44babf4a36c47496c4e77d701a302ef19a8923 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: R test/unittest/builtinvar/tst.caller.d A test/unittest/variables/bvar/tst.caller-dtrace.d A test/unittest/variables/bvar/tst.caller-dtrace.r R test/unittest/variables/bvar/tst.caller.d A test/unittest/variables/bvar/tst.stackdepth-dtrace.d A test/unittest/variables/bvar/tst.stackdepth-dtrace.r R test/unittest/variables/bvar/tst.stackdepth.d Log Message: ----------- test: caller and stackdepth tests for dtrace provider Also, a few old tests, which tested caller and stackdepth using the dtrace provider, are now superfluous given the new, provider-named tests. The old tests were extremely lenient -- e.g., simply checking that these built-in variables were not -1, even though both variables are unsigned anyhow! Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: 4350d2acee6e7629e20a953e6a59ddf1a7ad52b9 https://github.com/oracle/dtrace-utils/commit/4350d2acee6e7629e20a953e6a59ddf1a7ad52b9 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: A test/unittest/variables/bvar/skip_rawtp_old.x A test/unittest/variables/bvar/tst.caller-rawtp.d A test/unittest/variables/bvar/tst.caller-rawtp.r A test/unittest/variables/bvar/tst.caller-rawtp.r.p A test/unittest/variables/bvar/tst.caller-rawtp.x A test/unittest/variables/bvar/tst.stackdepth-rawtp.d A test/unittest/variables/bvar/tst.stackdepth-rawtp.r A test/unittest/variables/bvar/tst.stackdepth-rawtp.r.p A test/unittest/variables/bvar/tst.stackdepth-rawtp.x Log Message: ----------- test: caller and stackdepth tests for rawtp provider Also, add skip_rawtp_old.x, to skip rawtp testing on older kernels for the reasons described in the file. Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: 0badfcd086f822f0210da0ccdd92b89cafabf528 https://github.com/oracle/dtrace-utils/commit/0badfcd086f822f0210da0ccdd92b89cafabf528 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: A test/unittest/variables/bvar/tst.caller-cpc.d A test/unittest/variables/bvar/tst.caller-cpc.r A test/unittest/variables/bvar/tst.caller-cpc.r.p A test/unittest/variables/bvar/tst.stackdepth-cpc.d A test/unittest/variables/bvar/tst.stackdepth-cpc.r A test/unittest/variables/bvar/tst.stackdepth-cpc.r.p Log Message: ----------- test: caller and stackdepth tests for cpc provider Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: 8b616886c4e8c9aa549b10efee101f1f3d3ecfd6 https://github.com/oracle/dtrace-utils/commit/8b616886c4e8c9aa549b10efee101f1f3d3ecfd6 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: A test/unittest/variables/bvar/tst.caller-ip.d A test/unittest/variables/bvar/tst.caller-ip.r A test/unittest/variables/bvar/tst.caller-ip.r.p A test/unittest/variables/bvar/tst.caller-ip.t A test/unittest/variables/bvar/tst.stackdepth-ip.d A test/unittest/variables/bvar/tst.stackdepth-ip.r A test/unittest/variables/bvar/tst.stackdepth-ip.r.p A test/unittest/variables/bvar/tst.stackdepth-ip.t Log Message: ----------- test: caller and stackdepth tests for ip provider Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: 0e1ee6ca1b0f7adf53c230e3947e1701c20cdb50 https://github.com/oracle/dtrace-utils/commit/0e1ee6ca1b0f7adf53c230e3947e1701c20cdb50 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: R test/unittest/builtinvar/tst.caller1.d A test/unittest/variables/bvar/tst.caller-profile.d A test/unittest/variables/bvar/tst.caller-profile.r A test/unittest/variables/bvar/tst.caller-profile.r.p A test/unittest/variables/bvar/tst.stackdepth-profile.d A test/unittest/variables/bvar/tst.stackdepth-profile.r A test/unittest/variables/bvar/tst.stackdepth-profile.r.p Log Message: ----------- test: caller and stackdepth tests for profile provider Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: 0a15fd0e636ca8bc2645ba8d3af64cb3751be919 https://github.com/oracle/dtrace-utils/commit/0a15fd0e636ca8bc2645ba8d3af64cb3751be919 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: A test/unittest/variables/bvar/tst.caller-sched.d A test/unittest/variables/bvar/tst.caller-sched.r A test/unittest/variables/bvar/tst.caller-sched.r.p A test/unittest/variables/bvar/tst.stackdepth-sched.d A test/unittest/variables/bvar/tst.stackdepth-sched.r A test/unittest/variables/bvar/tst.stackdepth-sched.r.p Log Message: ----------- test: caller and stackdepth tests for sched provider Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: 4b29eafb866288cf57885b62447ce32cf3d1ad6e https://github.com/oracle/dtrace-utils/commit/4b29eafb866288cf57885b62447ce32cf3d1ad6e Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: A test/unittest/variables/bvar/tst.caller-proc.d A test/unittest/variables/bvar/tst.caller-proc.r A test/unittest/variables/bvar/tst.caller-proc.r.p A test/unittest/variables/bvar/tst.stackdepth-proc.d A test/unittest/variables/bvar/tst.stackdepth-proc.r A test/unittest/variables/bvar/tst.stackdepth-proc.r.p Log Message: ----------- test: caller and stackdepth tests for proc provider Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: f2a056c905b0e5d2aadf73372ae16c5e1347a822 https://github.com/oracle/dtrace-utils/commit/f2a056c905b0e5d2aadf73372ae16c5e1347a822 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: A test/unittest/variables/bvar/tst.caller-rawfbt.d A test/unittest/variables/bvar/tst.caller-rawfbt.r A test/unittest/variables/bvar/tst.caller-rawfbt.r.p A test/unittest/variables/bvar/tst.stackdepth-rawfbt.d A test/unittest/variables/bvar/tst.stackdepth-rawfbt.r A test/unittest/variables/bvar/tst.stackdepth-rawfbt.r.p Log Message: ----------- test: caller and stackdepth tests for rawfbt provider Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: b6294ac56cb85981531e16d43739747ea913eac1 https://github.com/oracle/dtrace-utils/commit/b6294ac56cb85981531e16d43739747ea913eac1 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: A test/unittest/variables/bvar/tst.caller-io.r A test/unittest/variables/bvar/tst.caller-io.r.p A test/unittest/variables/bvar/tst.caller-io.sh A test/unittest/variables/bvar/tst.caller-io.x A test/unittest/variables/bvar/tst.stackdepth-io.r A test/unittest/variables/bvar/tst.stackdepth-io.r.p A test/unittest/variables/bvar/tst.stackdepth-io.sh A test/unittest/variables/bvar/tst.stackdepth-io.x Log Message: ----------- test: caller and stackdepth tests for io provider Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Commit: 162b818df69c3608cbc1757fdf30d29927306c36 https://github.com/oracle/dtrace-utils/commit/162b818df69c3608cbc1757fdf30d29927306c36 Author: Eugene Loh Date: 2025-06-25 (Wed, 25 Jun 2025) Changed paths: A test/unittest/variables/bvar/skip_lockstat_5.10.x A test/unittest/variables/bvar/tst.caller-lockstat.d A test/unittest/variables/bvar/tst.caller-lockstat.r A test/unittest/variables/bvar/tst.caller-lockstat.r.p A test/unittest/variables/bvar/tst.caller-lockstat.t A test/unittest/variables/bvar/tst.caller-lockstat.x A test/unittest/variables/bvar/tst.stackdepth-lockstat.d A test/unittest/variables/bvar/tst.stackdepth-lockstat.r A test/unittest/variables/bvar/tst.stackdepth-lockstat.r.p A test/unittest/variables/bvar/tst.stackdepth-lockstat.t A test/unittest/variables/bvar/tst.stackdepth-lockstat.x Log Message: ----------- test: caller and stackdepth tests for lockstat provider Signed-off-by: Eugene Loh Reviewed-by: Nick Alcock Compare: https://github.com/oracle/dtrace-utils/compare/f0e1424fa41b...162b818df69c 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 Thu Jun 26 15:09:51 2025 From: kris.van.hees at oracle.com (Kris Van Hees) Date: Thu, 26 Jun 2025 11:09:51 -0400 Subject: [DTrace-devel] [RELEASE] DTrace 2.0.3 Message-ID: We are happy to announce the availability of DTrace for Linux 2.0.3! This new version is based on BPF and other Linux kernel tracing features and is implemented entirely as a userspace application. It can be used for tracing on any Linux kernel that provides BPF based tracing and BTF type data, although (as mentioned below) improved functionality depends on two (optional) kernel patches. The functionality is close to being feature-complete in comparison with the kernel module based version of DTrace for Linux (version 1.2.1-1). Development continues in an incremental fashion to make the full feature set of DTrace available using existing kernel features. WHERE TO FIND IT? The new version of DTrace for Linux is available at: https://github.com/oracle/dtrace-utils/tree/2.0-branch-dev The main development branch for DTrace for Linux is at: https://github.com/oracle/dtrace-utils/tree/devel The most recent release tag is 2.0.3. FEATURES - Providers: + cpc: CPU Performacne Counter probes + dtrace: BEGIN, END, and ERROR probes + fbt: Function Boundary Tracing (FBT) probes (Using fentry/fexit probes where available) + lockstat: Locking realted probes + pid: Userspace function boundary tracing and offset-based instruction probes + proc: Process lifecycle related probes + profile: Timer-based profile-* and tick-* probes + rawfbt: Function BOundary Tracing style provider that always uses kprobes - it can be used to trace . symbols that are generated by compiler optimizations + rawtp: SDT-style probes for kernel tracepoints with access to raw (untranslated) tracepoint arguments + sched: CPU scheduling probes [partial implementation] + sdt: Statically Defined Tracing (SDT) probes for kernel tracepoints + sycall: System call entry and exit probes + usdt: Userspace Statically Defined Tracing (USDT) probes + [NEW] usdt: probes definitions are now stored in ELF note data, to ensure compilation with LTO retains this data + [NEW] Command line arguments to the current task can now be accessed using the psinfo->pr_psargs translator member. + [NEW] Dynamic kprobe/fprobe selection for FBT has been corrected. + [NEW] pid: Support for absolute offset probes (using "-" as function name). + [NEW] fbt/rawfbt: Significant performance improvements to reduce the dtrace startup time during probe discovery. - Aggregations: + Regular and indexed aggregations + Aggregation functions: avg, count, llquantize, lquantize, max, min, quantize, stddev, and sum. + Aggregation actions: clear, normalize, normalize, printa - Speculative tracing: + Functions: speculation, speculate, commit, and discard - Variables: + Global variables + Thread-Local Storage (TLS) variables + Clause-local variables + Associative arrays for global and TLS variables + Full support for NULL-strings + Built-in: arg0 - arg9, args[], caller, curcpu, curthread, epid, errno, execname, gid, id, pid, ppid, probefunc, probemod, probename, probeprov, stackdepth, tid, timestamp, ucaller, uid, uregs[], ustackdepth, walltimestamp - Actions: + exit, freopen, ftruncate, mod, print, printa, printf, raise, setopt, stack, sym, system, trace, tracemem, uaddr, umod, ustack, usym - Subroutines: + alloca, basename, bcopy, cleanpath, copyin, copyinstr, copyinto, copyout, copyoutstr, dirname, d_path [dummy], getmajor, getminor, htonl, htonll, htons, index, inet_ntoa, link_ntop, lltostr, mutex_owned, mutex_owner, mutex_type_adaptive, mutex_type_spin, ntohl, ntohll, ntohs, progenyof, rand, rindex, rw_iswriter, rw_read_held, rw_write_held, strchr, strjoin, strlen, strrchr, strstr, strtok, substr - Runtime features: + Reporting of drop-counters for trace data that could not be recorded for the principal buffer, aggregation buffers, and speculation buffers. + Pre-generated translator files to support kernels from 5.2 to current. - BPF support: + Direct compilation of D source code into BPF programs. + Efficient use of pre-compiled BPF functions for library functions. + A bpflog option to request the BPF verifier log for loaded programs. + BPF program linking of dynamically generated code and pre-compiled code to facilitate code sharing and code re-use. + Improved integrated disassembler for generated BPF code at the clause and program level (-S in combination with the new -xdisasm=# option). + Improved trace data buffer handling based on memory mapped perf event ring-buffers. + BTF type data support. + [NEW] Precompiled BPF code is more granular to reduce BPF program size in generated tracing programs. - Development and debugging: + Support to run dtrace under valgrind. + Configure script based building is supported. + Improved support for building and using DTrace on upstream kernels. + Installation paths for all components are configurable. + Header files for USDT (sdt.h, etc) have been moved to avoid conflicts with projects that supply files with the same name. DEPENDENCIES DTrace for Linux depends on libctf (part of newer binutils) -or- libdtrace-ctf. While libctf is preferred, building against libdtrace-ctf is still possible. It can be found at: https://github.com/oracle/libdtrace-ctf DTrace for Linux makes use of BPF library functions that are compiled at build time. It depends on BPF support in GCC and binutils to generate the pre-compiled BPF function library. DTrace for Linux benefits from 2 optional kernel features that are not commonly available in Linux kernels: - CTF data generation at compile time: this provides important datatype information for kernel and kernel module symbols. - Module symbol address range data: this adds address range data about any built-in modules to allow for consistent ways to refer to probes by module and function (or probe) name. DTrace for Linux can be used for tracing without these patches, albeit with some limitations. These additional support features for tracing are available at: https://github.com/oracle/dtrace-linux-kernel/tree/v2/6.7 Please consider joining our development list: dtrace at lists.linux.dev and/or our IRC channel: #linux-dtrace at libera.chat Enjoy! From eugene.loh at oracle.com Sat Jun 28 01:19:32 2025 From: eugene.loh at oracle.com (eugene.loh at oracle.com) Date: Fri, 27 Jun 2025 21:19:32 -0400 Subject: [DTrace-devel] [PATCH] Make sure all probes are listed in default case Message-ID: <20250628011932.23469-1-eugene.loh@oracle.com> From: Eugene Loh Signed-off-by: Eugene Loh --- INCOMPATIBILITIES | 2 +- cmd/dtrace.c | 11 +++ test/unittest/dtrace-util/tst.ListProbes.r | 13 ++++ test/unittest/dtrace-util/tst.ListProbes.sh | 82 +++++++++++++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 test/unittest/dtrace-util/tst.ListProbes.r create mode 100755 test/unittest/dtrace-util/tst.ListProbes.sh diff --git a/INCOMPATIBILITIES b/INCOMPATIBILITIES index 035c3675b..bf55019ec 100644 --- a/INCOMPATIBILITIES +++ b/INCOMPATIBILITIES @@ -8,7 +8,7 @@ Missing providers Difficulty: Medium Likelihood: High -A number of providers are missing, including pid, fbt, and net. +Some providers are missing. diff --git a/cmd/dtrace.c b/cmd/dtrace.c index e0e778db0..ed517abff 100644 --- a/cmd/dtrace.c +++ b/cmd/dtrace.c @@ -1443,6 +1443,17 @@ main(int argc, char *argv[]) list_prog(&g_cmdv[i]); if (g_cmdc == 0) { + dtrace_cmd_t pseudo_cmd; + + /* + * If we are listing the default case "dtrace -l", + * compile the string ":::" to give providers an + * attempt to provide probes. + */ + pseudo_cmd.dc_spec = DTRACE_PROBESPEC_NAME; + pseudo_cmd.dc_arg = ":::"; + compile_str(&pseudo_cmd); + if (dtrace_probe_iter(g_dtp, NULL, list_probe, NULL) < 0) dfatal(NULL); /* dtrace_errmsg() only */ } diff --git a/test/unittest/dtrace-util/tst.ListProbes.r b/test/unittest/dtrace-util/tst.ListProbes.r new file mode 100644 index 000000000..a04669843 --- /dev/null +++ b/test/unittest/dtrace-util/tst.ListProbes.r @@ -0,0 +1,13 @@ +cpc +dtrace +fbt +io +ip +lockstat +proc +profile +rawfbt +rawtp +sched +sdt +syscall diff --git a/test/unittest/dtrace-util/tst.ListProbes.sh b/test/unittest/dtrace-util/tst.ListProbes.sh new file mode 100755 index 000000000..84f363443 --- /dev/null +++ b/test/unittest/dtrace-util/tst.ListProbes.sh @@ -0,0 +1,82 @@ +#!/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. +# + +## +# ASSERTION: +# Testing -l option gives reasonable numbers of probes for each provider. +# +# SECTION: dtrace Utility/-ln Option +## + +dtrace=$1 + +# Decide whether to expect lockstat (disabled prior to 5.10). +read MAJOR MINOR <<< `uname -r | grep -Eo '^[0-9]+\.[0-9]+' | tr '.' ' '` +if [ $MAJOR -gt 5 ]; then + expect_lockstat=1 +elif [ $MAJOR -eq 5 -a $MINOR -ge 10 ]; then + expect_lockstat=1 +else + expect_lockstat=0 +fi + +# Run "dtrace -l", print the providers, aggregate by provider, then confirm counts. +$dtrace $dt_flags -l \ +| gawk '{ print $2 }' \ +| sort | uniq -c \ +| gawk -v LCKSTT=$expect_lockstat ' + + BEGIN { + nerr = 0; + + # Fake lockstat if not expected. + if (LCKSTT == 0) print "lockstat"; + } + + function mycheck(lbl, val, valmin, valmax) { + print lbl; + if (val < valmin) { print "ERROR:", lbl, val, "< MIN =", valmin; nerr++ } + if (val > valmax) { print "ERROR:", lbl, val, "> MAX =", valmax; nerr++ } + } + + # Skip the banner. + /^ +1 PROVIDER$/ { next } + + # Wrong number of fields. + NF != 2 { + print "ERROR: wrong number of fields", $0; + nerr++; + next; + } + + # Recognize some providers; apply sanity check on number of probes. + $2 == "cpc" { mycheck($2, $1, 5, 500); next } + $2 == "dtrace" { mycheck($2, $1, 3, 3); next } + $2 == "fbt" { mycheck($2, $1, 30000, 300000); next } + $2 == "io" { mycheck($2, $1, 2, 20); next } + $2 == "ip" { mycheck($2, $1, 2, 20); next } + $2 == "lockstat" { mycheck($2, $1, 4, 40); next } + # nothing for pid + $2 == "proc" { mycheck($2, $1, 6, 30); next } + $2 == "profile" { mycheck($2, $1, 6, 30); next } + $2 == "rawfbt" { mycheck($2, $1, 30000, 300000); next } + $2 == "rawtp" { mycheck($2, $1, 600, 6000); next } + $2 == "sched" { mycheck($2, $1, 3, 30); next } + $2 == "sdt" { mycheck($2, $1, 600, 6000); next } + $2 == "syscall" { mycheck($2, $1, 300, 3000); next } + # nothing for usdt + + # Unrecognized line. + { + print "ERROR: unrecognized line", $0; + nerr++; + } + + END { exit(nerr == 0 ? 0 : 1) }' + +exit $? -- 2.43.5