{"id":19982056,"url":"https://github.com/hywan/sonde-rs","last_synced_at":"2026-01-04T09:31:03.647Z","repository":{"id":264926305,"uuid":"857005837","full_name":"Hywan/sonde-rs","owner":"Hywan","description":"A library to compile USDT probes into a Rust library","archived":false,"fork":false,"pushed_at":"2024-09-13T16:20:21.000Z","size":57,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-29T20:20:55.425Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Hywan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-13T16:11:54.000Z","updated_at":"2024-09-13T17:03:16.000Z","dependencies_parsed_at":"2024-11-27T00:01:08.663Z","dependency_job_id":null,"html_url":"https://github.com/Hywan/sonde-rs","commit_stats":null,"previous_names":["hywan/sonde-rs"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hywan%2Fsonde-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hywan%2Fsonde-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hywan%2Fsonde-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hywan%2Fsonde-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hywan","download_url":"https://codeload.github.com/Hywan/sonde-rs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252293082,"owners_count":21724960,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dtrace","ebpf","probe","rust","rust-lang","rust-library","usdt"],"created_at":"2024-11-13T04:08:55.243Z","updated_at":"2026-01-04T09:31:03.610Z","avatar_url":"https://github.com/Hywan.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cimg src=\"./image/logo.jpg\" width=\"300px\" /\u003e\u003cbr /\u003e\n  sonde\n\u003c/h1\u003e\n\n[![crates.io](https://img.shields.io/crates/v/sonde)](https://crates.io/crates/sonde)\n[![documentation](https://img.shields.io/badge/doc-sonde-green)](https://docs.rs/sonde)\n\n`sonde` is a library to compile USDT probes into a Rust library, and\nto generate a friendly Rust idiomatic API around it.\n\n[Userland Statically Defined Tracing][usdt] probes (USDT for short) is\na technique inherited from [DTrace] (see [OpenDtrace] to learn\nmore). It allows user to define statically tracing probes in their own\napplication; while they are traditionally declared in the kernel.\n\nUSDT probes can be naturally consumed with DTrace, but also with\n[eBPF] (`bcc`, `bpftrace`…).\n\n## Lightweight probes by design\n\nUSDT probes for libraries and executables are defined in an ELF\nsection in the corresponding application binary. A probe is translated\ninto a `nop` instruction, and its metadata are stored in the ELF's\n`.note.stapstd` section. When registering a probe, USDT tool (like\n`dtrace`, `bcc`, `bpftrace` etc.) will read the ELF section, and\ninstrument the instruction from `nop` to `breakpoint`, and after that,\nthe attached tracing event is run. After deregistering the probe, USDT\nwill restore the `nop` instruction from `breakpoint`.\n\nThe overhead of using USDT probes is almost zero when no tool is\nlistening the probes, otherwise a tiny overhead can be noticed.\n\n## The workflow\n\nEverything is automated. `dtrace` must be present on the system at\ncompile-time though. Let's imagine the following `sonde-test`\nfictitious project:\n\n```\n/sonde-test\n├── src\n│  ├── main.rs\n├── build.rs\n├── Cargo.toml\n├── provider.d\n```\n\nStart with the obvious thing: let's add the following lines to the\n`Cargo.toml` file:\n\n```toml\n[build-dependencies]\nsonde = \"0.1\"\n```\n\nNow, let's see what is in the `provider.d` file. It's _not_ a `sonde`\nspecific vendor format, it's the canonical way to declare USDT probes\n(see [Scripting][scripting])!\n\n```d\nprovider hello {\n    probe world(); \n    probe you(char*, int);\n};\n```\n\nIt describes a probe provider, `hello`, with two probes:\n\n1. `world`,\n2. `you` with 2 arguments: `char*` and `int`.\n\nBe careful, D types aren't the same as C types, even if they look like\nthe same.\n\nAt this step, one needs to play with `dtrace -s` to compile the probes\ninto systemtrap headers or an object file, but forget about that,\n`sonde` got you covered. Let's see what's in the `build.rs` script:\n\n```rust\nfn main() {\n    sonde::Builder::new()\n        .file(\"./provider.d\")\n        .compile();\n}\n```\n\nThat's all. That's the minimum one needs to write to make it\nwork.\n\nUltimately, we want to fire this probe from our code. Let's see what's\ninside `src/main.rs` then:\n\n```rust\n// Include the friendly Rust idiomatic API automatically generated by\n// `sonde`, inside a dedicated module, e.g. `tracing`.\nmod tracing {\n    include!(env!(\"SONDE_RUST_API_FILE\"));\n}\n\nfn main() {\n    tracing::hello::world();\n\n    println!(\"Hello, World!\");\n}\n```\n\nWhat can we see here? The `tracing` module contains a `hello` module,\ncorresponding to the `hello` provider. And this module contains a\n`world` function, corresponding to the `world` probe. Nice!\n\n\u003cdetails\u003e\n\u003csummary\u003eSee what's contained by the file pointed by \u003ccode\u003eSONDE_RUST_API_FILE\u003c/code\u003e:\u003c/summary\u003e\n\n```rust\n/// Bindings from Rust to the C FFI small library that calls the\n/// probes.\n\nuse std::os::raw::*;\n\nextern \"C\" {\n    #[doc(hidden)]\n    fn hello_probe_world();\n\n    #[doc(hidden)]\n    fn hello_probe_you(arg0: *mut c_char, arg1: c_int);\n}\n\n/// Probes for the `hello` provider.\npub mod r#hello {\n    use std::os::raw::*;\n\n    /// Call the `world` probe of the `hello` provider.\n    pub fn r#world() {\n        unsafe { super::hello_probe_world() };\n    }\n\n    /// Call the `you` probe of the `hello` provider.\n    pub fn r#you(arg0: *mut c_char, arg1: c_int) {\n        unsafe { super::hello_probe_you(arg0, arg1) };\n    }\n}\n```\n\n\u003c/details\u003e\n\nLet's see it in action:\n\n```sh\n$ cargo build --release\n$ sudo dtrace -l -c ./target/release/sonde-test | rg sonde-test\n123456 hello98765 sonde-test hello_probe_world world\n```\n\nNeat! Our `sonde-test` binary contains a `world` probe from the\n`hello` provider!\n\n```sh\n$ # Let's execute `sonde-test` as usual.\n$ ./target/release/sonde-test\nHello, World!\n$\n$ # Now, let's execute it with `dtrace` (or any other tracing tool).\n$ # Let's listen the `world` probe and prints `gotcha!` when it's executed.\n$ sudo dtrace -n 'hello*:::world { printf(\"gotcha!\\n\"); }' -q -c ./target/release/sonde-test\nHello, World!\ngotcha!\n```\n\nEh, it works! Let's try with the `you` probe now:\n\n```rust\nfn main() {\n    {\n        let who = std::ffi::CString::new(\"Gordon\").unwrap();\n        tracing::hello::you(who.as_ptr() as *mut _, who.as_bytes().len() as _);\n    }\n\n    println!(\"Hello, World!\");\n}\n```\n\nTime to show off:\n\n```sh\n$ cargo build --release\n$ sudo dtrace -n 'hello*:::you { printf(\"who=`%s`\\n\", stringof(copyin(arg0, arg1))); }' -q -c ./target/release/sonde-test\nHello, World!\nwho=`Gordon`\n```\n\nSuccessfully reading a string from Rust inside a USDT probe!\n\nWith `sonde`, you can add as many probes inside your Rust library or\nbinary as you need by simply editing your canonical `.d` file.\n\nBonus: `sonde` generates documentation for your probes\nautomatically. Run `cargo doc --open` to check.\n\n## Possible limitations\n\n### Types\n\nDTrace has its own type system (close to C) (see [Data Types and\nSizes][data-types]). `sonde` tries to map it to the Rust system as\nmuch as possible, but it's possible that some types could not\nmatch. The following types are supported:\n\n| Type Name in D | Type Name in Rust |\n|-|-|\n| `char` | `std::os::raw::c_char` |\n| `short` | `std::os::raw::c_short` |\n| `int` | `std::os::raw::c_int` |\n| `long` | `std::os::raw::c_long` |\n| `long long` | `std::os::raw::c_longlong` |\n| `int8_t` | `i8` |\n| `int16_t` | `i16` |\n| `int32_t` | `i32` |\n| `int64_t` | `i64` |\n| `intptr_t` | `isize` |\n| `uint8_t` | `u8` |\n| `uint16_t` | `u16` |\n| `uint32_t` | `u32` |\n| `uint64_t` | `u64` |\n| `uintptr_t` | `usize` |\n| `float` | `std::os::raw::c_float` |\n| `double` | `std::os::raw::c_double` |\n| `T*` | `*mut T` |\n| `T**` | `*mut *mut T` (and so on) |\n\n### Parser\n\nThe `.d` files are parsed by `sonde`. For the moment, only the\n`provider` blocks are parsed, which declare the `probe`s. All the\npragma (`#pragma`) directives are ignored for the moment.\n\n## License\n\n`BSD-3-Clause`, see `LICENSE.md`.\n\n\n[usdt]: https://illumos.org/books/dtrace/chp-usdt.html\n[DTrace]: https://en.wikipedia.org/wiki/DTrace\n[OpenDtrace]: https://github.com/opendtrace/opendtrace\n[eBPF]: http://www.brendangregg.com/blog/2019-01-01/learn-ebpf-tracing.html\n[data-types]: https://illumos.org/books/dtrace/chp-typeopexpr.html#chp-typeopexpr-2\n[`std::os::raw`]: https://doc.rust-lang.org/std/os/raw/index.html\n[scripting]: https://illumos.org/books/dtrace/chp-script.html#chp-script\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhywan%2Fsonde-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhywan%2Fsonde-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhywan%2Fsonde-rs/lists"}