Re: [PATCH] doc: Add stapsdt provider documentation

Alan Maguire
2025-11-18T12:43:22Z

On 18/11/2025 04:30, eugene.loh@oracle.com wrote:
> From: Eugene Loh <eugene.loh@oracle.com>
>
> Signed-off-by: Eugene Loh <eugene.loh@oracle.com>

looks great, a few small suggestions below, but

Reviewed-by: Alan Maguire <alan.maguire@oracle.com>

> ---
> doc/userguide/index.md | 4 +
> doc/userguide/reference/dtrace_providers.md | 4 +-
> .../reference/dtrace_providers_stapsdt.md | 154 ++++++++++++++++++
> 3 files changed, 161 insertions(+), 1 deletion(-)
> create mode 100644 doc/userguide/reference/dtrace_providers_stapsdt.md
>
> diff --git a/doc/userguide/index.md b/doc/userguide/index.md
> index da9a08687..3e057d4de 100644
> --- a/doc/userguide/index.md
> +++ b/doc/userguide/index.md
> @@ -259,6 +259,10 @@
> - [Declaring Probes](reference/dtrace_providers_sdt.md#dt_ref_sdtdeclp_prov)
> - [sdt Probe Arguments](reference/dtrace_providers_sdt.md#dt_ref_sdtparg_prov)
> - [sdt Stability](reference/dtrace_providers_sdt.md#dt_ref_sdtstab_prov)
> + - [Stapsdt Provider](reference/dtrace_providers_stapsdt.md)
> + - [stapsdt Probes](reference/dtrace_providers_stapsdt.md#dt_ref_stapsdtprobes_prov)
> + - [stapsdt Examples](reference/dtrace_providers_stapsdt.md#dt_ref_stapsdtexamples_prov)
> + - [stapsdt Stability](reference/dtrace_providers_stapsdt.md#dt_ref_stapsdtstab_prov)
> - [Syscall Provider](reference/dtrace_providers_syscall.md#dt_ref_syscall_prov)
> - [syscall Probes](reference/dtrace_providers_syscall.md#dt_ref_syscallprobes_prov)
> - [syscall Probe Arguments](reference/dtrace_providers_syscall.md#dt_ref_syscallargs_prov)
> diff --git a/doc/userguide/reference/dtrace_providers.md b/doc/userguide/reference/dtrace_providers.md
> index 45623d92f..2f6aa877a 100644
> --- a/doc/userguide/reference/dtrace_providers.md
> +++ b/doc/userguide/reference/dtrace_providers.md
> @@ -29,10 +29,12 @@ The `rawtp` provider gives DTrace users access to the raw tracepoints exposed by
> The `sched` provider makes available probes related to CPU scheduling.
> - **[SDT Provider](../reference/dtrace_providers_sdt.md)**
> The Statically Defined Tracing \(SDT\) provider \(`sdt`\) creates probes at sites that a software programmer has formally designated. Thus, the SDT provider is chiefly of interest only to developers of new providers. Most users access SDT only indirectly by using other providers.
> +- **[Stapsdt Provider](../reference/dtrace_providers_stapsdt.md)**
> +The `stapsdt` provider makes available probes for static instrumentation points in ELF notes of binaries.
> - **[Syscall Provider](../reference/dtrace_providers_syscall.md)**
> The `syscall` provider makes available a probe at the entry to and return from every system call in the system.
> - **[TCP Provider](../reference/dtrace_providers_tcp.md)**
> -The `tcp` provider makes available probe at different phases of TCP processing.
> +The `tcp` provider makes available probes at different phases of TCP processing.
> - **[UDP Provider](../reference/dtrace_providers_udp.md)**
> The `udp` provider makes available a probe at UDP send and receive operations in the system.
> - **[USDT Provider](../reference/dtrace-ref-StaticallyDefinedTracingofUserApplications.md)**
> diff --git a/doc/userguide/reference/dtrace_providers_stapsdt.md b/doc/userguide/reference/dtrace_providers_stapsdt.md
> new file mode 100644
> index 000000000..43e442358
> --- /dev/null
> +++ b/doc/userguide/reference/dtrace_providers_stapsdt.md
> @@ -0,0 +1,154 @@
> +
> +# Stapsdt Provider
> +
> +The `stapsdt` provider allows DTrace to read ELF notes for binaries, using
> +`/proc/` maps associated with processes, and parse them to retrieve `uprobe`
> +addresses and argument-related information to create the associated `uprobe`.
> +That is, the provider allows DTrace to probe programs and libraries that
> +contain static probes that were added via `stapsdt` ELF notes.
> +
> +Note that `stapsdt` probes do not dynamically register themselves with DTrace,
> +making them less powerful than DTrace-based USDT probes.
> +
> +**Parent topic:**[DTrace Provider Reference](../reference/dtrace_providers.md)
> +
> +## stapsdt Probes
> +
> +You may not be interested in inserting probes into source code yourself,
> +but simply taking advantage of static probes inserted into the ELF notes
> +of binaries and libraries by other developers. For example, probes for DTrace
> +and SystemTap were added to Python as far back as Python 3.6 provided
> +Python is built with [`--with-dtrace`](https://docs.python.org/3/howto/instrumentation.html).
> +
> +Alternatively, you can insert your own probe into application or library
> +source code as follows:
> +
> +```
> +#define _SDT_HAS_SEMAPHORES 1
> +#include <sys/sdt.h>
> +
> +unsigned short myprovider_myprobe_semaphore = 0;
> +
> + if (myprovider_myprobe_semaphore) {
> + STAP_PROBEn(myprovider, myprobe, ...);
> + }
> +```
> +
> +The *semaphore* portions are only needed if you want to test at run time
> +whether the probe is enabled; this can reduce run-time overheads for cases
> +where a probe is not enabled.

Here I would mention the value proposition is that we can then do any
extra work needed to assemble information for probe arguments, and
criticially then this work will not be done if no probes are enabled.
Otherwise there's no real value in the semaphore support. More on that
below in your example..

Maybe it is too much detail, but it might be worth mentioning that the
sempahore _counting_ is handled by the kernel on probe enable/disable,
we just need to ensure it is defined as above and DTrace will pass
semaphore details to the kernel for reference counting.

> The `...` indicate the probe arguments; note that
> +`STAP_PROBEn` should be replaced by `STAP_PROBE`, `STAP_PROBE1`, `STAP_PROBE2`,
> +`STAP_PROBE3`, etc., depending on how many probe arguments there are.
> +
> +The `stapsdt` provider also supports probes created dynamically via `libstapsdt`.
> +See [https://github.com/linux-usdt/libstapsdt](https://github.com/linux-usdt/libstapsdt).
> +
> +In your D scripts, the provider name must have the pid for your process
> +appended. For the provider shown above, you might have `myprovider12345`
> +for pid 12345. No wildcard may be used, but a symbolic value like `$target` may.
> +
> +In your D scripts, the `stapsdt` module name may be `a.out` just as one can
> +with the [`pid` provider](dtrace_providers_pid.md#dt_ref_pidprobes_prov).
> +
> +## stapsdt Examples
> +
> +For example, consider this sample source code, which could represent the instrumentation one
> +might place in application or library source code:
> +
> +```
> +#include <stdio.h>
> +#define _SDT_HAS_SEMAPHORES 1
> +#include <sys/sdt.h>
> +
> +unsigned short myprovider_myprobe_semaphore = 0;
> +
> +int
> +main(int argc, char **argv)
> +{
> + STAP_PROBE3(myprovider, myprobe, argc, argv[0], 18);
> + if (myprovider_myprobe_semaphore)
> + printf("the probe is enabled\n");
> + else
> + printf("the probe is not enabled\n");
> +
> + return 0;
> +}
> +```
> +

I found the example a bit confusing. I would have thought:

> +int
> +main(int argc, char **argv)
> +{
> + if (myprovider_myprobe_semaphore) {
> + printf("the probe is enabled\n");
> + STAP_PROBE3(myprovider, myprobe, argc, argv[0], 18);
> + } else
> + printf("the probe is not enabled\n");
> +

? The semaphore should always guard the probe it is related to.

Maybe to make the notion of doing extra work in the semaphore case we
could do something extra in the is-enabled clause, like concat all the
arguments into a string which we pass to the probe instead of argv[0]?

> +Assuming it is called `test.c`, compile with `gcc test.c`.
> +
> +We can then run `dtrace -l` to list the available probes,
> +assuming we specify the pid-specific provider (in this case using
> +the `$target` symbolic name):
> +
> +```
> +$ sudo /usr/sbin/dtrace -c ./a.out -lvP 'myprovider$target'
> + ID PROVIDER MODULE FUNCTION NAME
> + 5067 myprovider2623420 a.out main myprobe
> + [...]
> + Argument Types
> + args[0]: int32_t
> + args[1]: uint64_t
> + args[2]: int32_t
> +```
> +

Nice, I didn't realize that worked to be honest!

> +Since we list the arguments with `-v`, we get information on the argument
> +types: the first and last arguments are 4-byte integers, while the middle argument
> +is 8 bytes (a `char *`).
> +
> +We can run the program without `dtrace` to confirm that the probe is
> +not enabled by default:
> +
> +```
> +$ ./a.out
> +the probe is not enabled
> +```
> +
> +Next, we run with `dtrace` and see that the probe *is* enabled and
> +that the probe arguments are `argc, argv[0], 18`, as indicated in
> +the `test.c` source code:
> +
> +```
> +$ sudo /usr/sbin/dtrace -c ./a.out -qn '
> +myprovider$target:::myprobe
> +{
> + printf("%li, %s, %li\n", arg0, copyinstr(arg1), arg2);
> +}'
> +the probe is enabled
> +1, ./a.out, 18
> +```
> +
> +Adventurous readers can use `readelf` to explore the ELF notes
> +more directly:
> +
> +```
> +$ readelf --notes a.out
> +[...]
> +Displaying notes found in: .note.stapsdt
> + Owner Data size Description
> + stapsdt 0x00000045 NT_STAPSDT (SystemTap probe descriptors)
> + Provider: myprovider
> + Name: myprobe
> + Location: 0x000000000040113c, Base: 0x000000000040203e, Semaphore: 0x0000000000404026
> + Arguments: -4@-4(%rbp) 8@%rax -4@$18
> +```
> +
> +Notice that the instrumented source code includes the header file
> +`<sys/sdt.h>`. On Oracle Linux, this file is installed
> +by the RPM package `systemtap-sdt-devel`, but the package also
> +installs `/usr/bin/dtrace`. So be sure to have `/usr/sbin`
> +in front of `/usr/bin` in your path, or explicitly specify
> +`/usr/sbin/dtrace` whenever you want to use `dtrace`.
> +

Would be good to mention that a double underscore "__" gets converted to
a dash (-) in provider/probe names too.

This is excellent stuff, thanks for doing it!

> +## stapsdt Stability
> +
> +The `stapsdt` provider uses DTrace's stability mechanism to describe its stabilities.
> +These values are listed in the following table.
> +
> +| Element | Name Stability | Data Stability | Dependency Class |
> +| :--- | :--- | :--- | :--- |
> +| Provider | Evolving | Evolving | ISA |
> +| Module | Private | Private | Unknown |
> +| Function | Private | Private | Unknown |
> +| Name | Evolving | Evolving | ISA |
> +| Arguments | Private | Private | Unknown |