A simple instrumentation-based trace tool for my own analysis needs.
Add xray
compiler flag to .cargo/config.toml
Requires Rust nightly-2025-05-28 or later for xray support on macOS. See PR #140790 for details.
rustflags = [
"-Zinstrument-xray=always",
]
Add setup crate
[dependencies]
sftrace-setup = { path = "../sftrace/setup" }
Initialize sftrace, which should be run before anything else
fn main() {
unsafe {
sftrace_setup::setup();
}
}
// or
#[ctor]
unsafe fn init_sftrace() {
unsafe {
sftrace_setup::setup();
}
}
If you need to record memory events, and need to configure the global allocator hook
#[global_allocator]
static A: sftrace_setup::SftraceAllocator<std::alloc::System> =
sftrace_setup::SftraceAllocator(std::alloc::System);
When compiling, we need to specify the directory where libsftrace.so
is located.
env SFTRACE_DYLIB_DIR="$TOPATH" cargo build
Run the program on specified environment variables
env LD_LIBRARY_PATH="$TOPATH" \
SFTRACE_OUTPUT_FILE="$OUTDIR/sf.log" \
your-program
In an ideal world, we wouldn't need to specify
LD_LIBRARY_PATH
. But right now rpath doesn't really work. see rust-lang/cargo#5077
Note that this may generate very large logs, which may require a lot of memory when analyzing. You can generate filter files to keep only the functions you are interested in.
sftrace filter -p your-program -o "$OUTDIR/sf.filter" -r "<regex rule>"
Specify the filter file when running the program
env ... \
SFTRACE_FILTER="$OUTDIR/sf.filter" \
your-program
We support macOS, but macOS doesn't support us.
You need to run the program on lldb (or any ptrace debugger).
lldb \
-O "env DYLD_LIBRARY_PATH=$TOPATH" \
-O "env SFTRACE_OUTPUT_FILE=$OUTDIR/sf.log" \
your-program
This is because the text segment can only be modified in ptrace (and dtrace).
You can convert it to perfetto protobuf format
sftrace convert "$OUTDIR/sf.log" -o trace.pb.gz
and I recommend using vizviewr
vizviewer --use_external_processor trace.pb.gz
This project is licensed under the MIT license.