A standalone Go library for working with User Statically-Defined Tracepoints (USDTs). Parse USDT probes from ELF binaries, extract argument specifications, and attach eBPF programs to probes at runtime.
- ELF probe parsing: Read
.note.stapsdtsections, apply prelink adjustments, convert virtual addresses to file offsets for uprobe attachment - Argument spec parsing: Decode USDT argument specifications (registers, memory dereferences, constants) for x86_64 and ARM64
- eBPF helpers: BPF-side headers for extracting USDT arguments at runtime (
BPF_USDT()macro,bpf_usdt_arg()) - CLI tool:
cmd/usdtfor inspecting probes in binaries from the command line
# Library
go get github.com/parca-dev/usdt
# CLI tool
go install github.com/parca-dev/usdt/cmd/usdt@latestprobes, err := usdt.ParseProbesFromFile("/usr/lib/libc.so.6")
if err != nil {
log.Fatal(err)
}
for _, p := range probes {
fmt.Printf("%s:%s at offset 0x%x args=%q\n",
p.Provider, p.Name, p.Location, p.Arguments)
}// Parse a USDT argument string like "-4@%esi 8@%rdi"
spec, err := usdt.ParseUSDTArguments("-4@%esi 8@%rdi")
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d arguments\n", spec.Arg_cnt)// Bring your own BPF objects (e.g. generated by bpf2go from your own .c sources).
probes, _ := usdt.ParseProbesFromFile(exePath)
// Populate the spec map so the BPF side can extract arguments.
specIDs, err := usdt.PopulateSpecMap(myObjs.BpfUsdtSpecs, probes, 1 /*startID*/)
// Optionally merge spec IDs with per-probe user cookies.
cookies := usdt.MergeCookies(specIDs, userCookies)
// Attach one BPF program per probe.
exe, _ := link.OpenExecutable(exePath)
pl, err := usdt.AttachUprobes(exe, myObjs.BpfUsdtSpecs, probes, progs, cookies)
defer pl.Close()Implement the ELFReader interface to use your own ELF parser:
type ELFReader interface {
Sections() ([]usdt.ELFSection, error)
LoadSegments() []usdt.ELFProg
}
probes, err := usdt.ParseProbes(myCustomReader)Include in your BPF programs for USDT argument extraction. The headers
intentionally pull in nothing — your own prelude (providing u8/u64/
bool/pt_regs/EBPF_INLINE and the BPF helper declarations) must be
included first. The bundled ebpf/kernel.h is one such prelude:
#include "kernel.h" // or your own equivalent
#include "usdt_args.h"
SEC("usdt/myprovider/myprobe")
int BPF_USDT(myprobe, s64 arg0, u64 arg1)
{
// arg0 and arg1 are automatically extracted
return 0;
}usdt_defs.h (struct/enum definitions only) can be included on its own
when you just need the userspace-visible layouts without the BPF helpers.
usdt list <binary> [flags] List USDT probes in an ELF binary
-provider string Filter by provider name
-name string Filter by probe name
-args Show raw argument strings
usdt parse-args <arg-string> Parse a USDT argument specification string
Examples:
# List all probes in a binary
usdt list /usr/bin/python3
# Show probes with their argument strings
usdt list --args /usr/bin/python3
# Filter by provider
usdt list --provider python /usr/bin/python3
# Inspect an argument spec string
usdt parse-args "-4@%esi 8@%rax -4@-24(%rbp)"# Generate eBPF objects and run tests
make
# Build the CLI tool (output: bin/usdt)
make build
# Regenerate after modifying BPF sources
make generate
# Run tests only
make test- Go 1.25+
- clang (for
go generate/ bpf2go BPF compilation) systemtap-sdt-dev(for test probes, providessys/sdt.h)- Requires Linux 5.15+ for bpf_get_attach_cookie
Apache License 2.0. See LICENSE for details.