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 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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
//! This crate provides static instrumentation macros.
//!
//! With the `probe!` macro, programmers can place static instrumentation
//! points in their code to mark events of interest. These are compiled into
//! platform-specific implementations, e.g. SystemTap SDT on Linux. Probes are
//! designed to have negligible overhead during normal operation, so they can
//! be present in all builds, and only activated using those external tools.
//!
//! # Example
//!
//! This simple example instruments the beginning and end of program, as well
//! as every iteration through the loop with arguments for the counter and
//! intermediate total.
//!
//! ```rust
//! use probe::probe;
//! fn main() {
//! probe!(foo, begin);
//! let mut total = 0;
//! for i in 0..100 {
//! total += i;
//! probe!(foo, loop, i, total);
//! }
//! assert_eq!(total, 4950);
//! probe!(foo, end);
//! }
//! ```
//!
//! ## Using probes with SystemTap
//!
//! For the program above, a SystemTap script could double-check the totals:
//!
//! ```notrust
//! global check
//!
//! probe process.provider("foo").mark("loop") {
//! check += $arg1;
//! if (check != $arg2)
//! printf("foo total is out of sync! (%d != %d)\n", check, $arg2);
//! }
//!
//! // .provider is optional
//! probe process.mark("begin"), process.mark("end") {
//! printf("%s:%s\n", $$provider, $$name);
//! }
//! ```
//!
//! Since this program behaves as expected, this script will not have any complaint.
//!
//! ```notrust
//! $ stap --dyninst foo.stp -c ./foo
//! foo:begin
//! foo:end
//! ```
//!
//! ## Using probes with GDB
//!
//! Starting in version 7.5, GDB can set breakpoints on probes and read arguments.
//!
//! ```notrust
//! (gdb) info probes
//! Provider Name Where Semaphore Object
//! foo begin 0x0000000000402e70 /tmp/foo
//! foo end 0x000000000040315c /tmp/foo
//! foo loop 0x0000000000402f25 /tmp/foo
//! (gdb) break -probe foo:loop
//! Breakpoint 1 at 0x402f25
//! (gdb) condition 1 $_probe_arg1 > 1000
//! (gdb) run
//! Starting program: /tmp/foo
//! [Thread debugging using libthread_db enabled]
//! Using host libthread_db library "/lib64/libthread_db.so.1".
//!
//! Breakpoint 1, 0x0000000000402f25 in main::hd67360886023c1c6faa::v0.0 ()
//! (gdb) print $_probe_arg0
//! $1 = 45
//! (gdb) print $_probe_arg1
//! $2 = 1035
//! ```
#![no_std]
mod platform;
/// Define a static probe point.
///
/// This annotates a code location with a name and arguments, and compiles
/// in metadata to let debugging tools locate it.
///
/// # Arguments
///
/// * `provider` - An identifier for naming probe groups.
///
/// * `name` - An identifier for this specific probe.
///
/// * `arg`... - Optional data to provide with the probe. Any expression which
/// can be cast `as isize` is allowed as an argument. The arguments might not
/// be evaluated at all when a debugger is not attached to the probe,
/// depending on the platform implementation, so don't rely on side effects.
///
/// # Example
///
/// ```
/// use probe::probe;
/// fn main() {
/// probe!(foo, main);
///
/// let x = 42;
/// probe!(foo, show_x, x);
///
/// let y = Some(x);
/// probe!(foo, show_y, match y {
/// Some(n) => n,
/// None => -1
/// });
/// }
/// ```
#[macro_export]
macro_rules! probe(
($provider:ident, $name:ident $(, $arg:expr)* $(,)?)
=> ($crate::platform_probe!($provider, $name, $($arg,)*));
);