aya: Add USDT documentation

Signed-off-by: Dave Tucker <dave@dtucker.co.uk>
pull/329/merge^2
Dave Tucker 3 years ago
parent 4c60210a2e
commit 68ca1e1f3f

@ -521,7 +521,9 @@ pub fn sk_lookup(attrs: TokenStream, item: TokenStream) -> TokenStream {
/// use aya_bpf::{macros::usdt, programs::UsdtContext}; /// use aya_bpf::{macros::usdt, programs::UsdtContext};
/// ///
/// #[usdt] /// #[usdt]
/// pub fn tick(_ctx: UsdtContext) -> u32 { /// pub fn tick(ctx: UsdtContext) -> u32 {
/// let arg = ctx.arg(0);
/// // Use aya-log to print the value to userspace
/// return 0 /// return 0
/// } /// }
/// ``` /// ```

@ -4,13 +4,16 @@ pub const USDT_MAX_SPEC_COUNT: u32 = 256;
pub const USDT_MAX_IP_COUNT: u32 = 4 * USDT_MAX_SPEC_COUNT; pub const USDT_MAX_IP_COUNT: u32 = 4 * USDT_MAX_SPEC_COUNT;
pub const USDT_MAX_ARG_COUNT: usize = 12; pub const USDT_MAX_ARG_COUNT: usize = 12;
/// The type of argument in a USDT program /// The type of argument in a USDT program.
#[repr(u32)] #[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "user", derive(Debug))] #[cfg_attr(feature = "user", derive(Debug))]
pub enum UsdtArgType { pub enum UsdtArgType {
/// Value is Constant.
Const, Const,
/// Value is stored in a Register.
Reg, Reg,
/// Value is stored in a Register and requires dereferencing.
RegDeref, RegDeref,
} }
@ -20,31 +23,37 @@ impl Default for UsdtArgType {
} }
} }
/// The specifcation of an argument in a USDT program /// The specifcation of an argument in a USDT program.
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Default, PartialEq, Eq)] #[derive(Copy, Clone, Default, PartialEq, Eq)]
#[cfg_attr(feature = "user", derive(Debug))] #[cfg_attr(feature = "user", derive(Debug))]
pub struct UsdtArgSpec { pub struct UsdtArgSpec {
/// scalar interpreted depending on arg_type /// Meaning of val_off differs based on `arg_type`.
/// If Constant, this holds the scalar value of unknow type, up to u64 in size.
/// If RegDeref, this contains an offset which is an i64.
pub val_off: u64, pub val_off: u64,
/// arg location case /// Type of Argument.
pub arg_type: UsdtArgType, pub arg_type: UsdtArgType,
/// offset of referenced register within struct pt_regs /// Offset of the register within the BPF context
pub reg_off: i16, pub reg_off: i16,
/// whether arg should be interpreted as signed value /// Whether the value should be interpreted as signed
pub arg_signed: bool, pub arg_signed: bool,
/// number of bits that need to be cleared and, optionally, /// Number of bits that need to be cleared and, optionally,
/// sign-extended to cast arguments that are 1, 2, or 4 bytes /// sign-extended to cast arguments that are 1, 2, or 4 bytes
/// long into final 8-byte u64/s64 value returned to user /// long into final 8-byte u64/s64 value returned to user.
pub arg_bitshift: i8, pub arg_bitshift: i8,
} }
/// The specification of a USDT
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "user", derive(Debug))] #[cfg_attr(feature = "user", derive(Debug))]
pub struct UsdtSpec { pub struct UsdtSpec {
/// Specification used to access arguments.
pub args: [UsdtArgSpec; USDT_MAX_ARG_COUNT], pub args: [UsdtArgSpec; USDT_MAX_ARG_COUNT],
/// User supplied cookie since the BPF Attach Cookie is used internally.
pub cookie: u64, pub cookie: u64,
/// Number of args in this tracepoint
pub arg_count: i16, pub arg_count: i16,
} }

@ -36,7 +36,50 @@ pub const USDT_SPEC_MAP: &str = "__bpf_usdt_specs";
/// Name of the map used for USDT to IP mappings. /// Name of the map used for USDT to IP mappings.
pub const USDT_IP_TO_SPEC_MAP: &str = "__bpf_usdt_ip_to_spec_id"; pub const USDT_IP_TO_SPEC_MAP: &str = "__bpf_usdt_ip_to_spec_id";
/// A user statically-defined tracepoint /// A user statically-defined tracepoint program.
///
/// USDT programs are the fastest of the userspace tracing programs and can be
/// used to trace events instrumented libraries or binaries. Unlike uprobes and
/// uretprobes that have access to all CPU registers, USDTs provide a structured
/// specification for accessing the arguments for each tracepoint. When compliled
/// a single tracepoint may have mutliple different entrypoints in the same program.
/// In order to simply access to arguments from eBPF, Aya keeps state in 2 maps:
///
/// - [`USDT_SPEC_MAP`] which keeps track of USDT specifications
/// - [`USDT_IP_TO_SPEC_MAP`] which keeps track of Instructio Pointers to USDT specs.
///
/// The last map is not used on kernels which support the BPF Attach Cookie feature.
///
/// # Minimum kernel version
///
/// While support was added to the kenel in 4.19, Aya depends on a feature that
/// allows the kernel to manage semaphore reference counting which was added in
/// 4.20.
///
/// The minimum supported kernel version is 4.20.
///
/// # Examples
///
/// ```no_run
/// # let mut bpf = Bpf::load_file("ebpf_programs.o")?;
/// use aya::{Bpf, programs::{Usdt, usdt::{USDT_SPEC_MAP, USDT_IP_TO_SPEC_MAP}}};
/// use aya::maps::{Array, HashMap};
/// use std::convert::TryInto;
///
/// let spec_map = Array::try_from(bpf.map_mut(USDT_SPEC_MAP).unwrap())?;
/// let ip_to_spec_map = HashMap::try_from(bpf.map_mut(USDT_IP_TO_SPEC_MAP).unwrap())?;
/// let program: &mut Usdt = bpf.program_mut("usdt").unwrap().try_into()?;
/// program.load()?;
/// program.attach(
/// spec_map,
/// ip_to_spec_map,
/// "clock",
/// "loop",
/// "/path/to/target/debug/clock",
/// Some(12345),
/// )?;
/// # Ok::<(), aya::BpfError>(())
/// ```
#[derive(Debug)] #[derive(Debug)]
#[doc(alias = "BPF_PROG_TYPE_KPROBE")] #[doc(alias = "BPF_PROG_TYPE_KPROBE")]
pub struct Usdt { pub struct Usdt {
@ -51,13 +94,19 @@ impl Usdt {
/// Attaches the program. /// Attaches the program.
/// ///
/// Attaches the uprobe to the tracepoint `tp_provider`/`tp_name` defined in the `target`. /// Attaches the USDT to the tracepoint with a matching `tp_provider` and `tp_name`
/// in the `target`.
///
/// If `pid` is not `None`, the program executes only when the target /// If `pid` is not `None`, the program executes only when the target
/// function is executed by the given `pid`. /// function is executed by the given `pid`. This is only supported in kernels which
/// provide the BPF Attach Cookie feature.
/// ///
/// The `target` argument can be an absolute path to a binary or library, or /// The `target` argument can be an absolute path to a binary or library, or
/// a library name (eg: `"libc"`). /// a library name (eg: `"libc"`).
/// ///
/// Since there a single tracepoint can have multiple entrypoints, a single `UsdtLinkId`
/// may be comprised of multiple links.
///
/// The returned value can be used to detach, see [Usdt::detach]. /// The returned value can be used to detach, see [Usdt::detach].
pub fn attach<T: AsRef<Path>>( pub fn attach<T: AsRef<Path>>(
&mut self, &mut self,
@ -158,11 +207,11 @@ impl Usdt {
/// The identifer of a MultiPerfLink. /// The identifer of a MultiPerfLink.
#[derive(Debug, Hash, Eq, PartialEq)] #[derive(Debug, Hash, Eq, PartialEq)]
pub struct MultiPerfLinkId(Vec<PerfLinkIdInner>); pub(crate) struct MultiPerfLinkId(Vec<PerfLinkIdInner>);
/// The attachment type of USDT programs. // A wrapper around multiple PerfLinkInner
#[derive(Debug)] #[derive(Debug)]
pub struct MultiPerfLink { pub(crate) struct MultiPerfLink {
perf_links: Vec<PerfLinkInner>, perf_links: Vec<PerfLinkInner>,
} }
@ -191,7 +240,7 @@ define_link_wrapper!(
MultiPerfLinkId MultiPerfLinkId
); );
/// The type returned when attaching an [`UProbe`] fails. /// The type returned when attaching a [`Usdt`] fails.
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum UsdtError { pub enum UsdtError {
/// There was an error parsing `/etc/ld.so.cache`. /// There was an error parsing `/etc/ld.so.cache`.
@ -384,6 +433,7 @@ fn find_segment_by_address<Elf: FileHeader<Endian = Endianness>>(
}) })
} }
// A resolved Usdt target.
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct UsdtTarget { pub(crate) struct UsdtTarget {
abs_ip: u64, abs_ip: u64,
@ -393,6 +443,7 @@ pub(crate) struct UsdtTarget {
spec: UsdtSpec, spec: UsdtSpec,
} }
// A parsed note from an ELF stapsdt note.
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct UsdtNote { pub(crate) struct UsdtNote {
loc_addr: u64, loc_addr: u64,

@ -29,23 +29,27 @@ pub struct UsdtContext {
} }
impl UsdtContext { impl UsdtContext {
/// Creates a new Usdtcontext.
pub fn new(ctx: *mut c_void) -> UsdtContext { pub fn new(ctx: *mut c_void) -> UsdtContext {
UsdtContext { UsdtContext {
regs: ctx as *mut pt_regs, regs: ctx as *mut pt_regs,
} }
} }
/// Access the register that holds the next instruction pointer.
#[inline(always)] #[inline(always)]
fn ip<T: FromPtRegs>(&self) -> Option<T> { fn ip<T: FromPtRegs>(&self) -> Option<T> {
T::from_ip(unsafe { &*self.regs }) T::from_ip(unsafe { &*self.regs })
} }
/// Access the spec_id from the BPF Attach Cookie.
#[cfg(feature = "cookie")] #[cfg(feature = "cookie")]
#[inline(always)] #[inline(always)]
fn spec_id(&self) -> Result<u32, ()> { fn spec_id(&self) -> Result<u32, ()> {
unsafe { Ok(aya_bpf_bindings::helpers::bpf_get_attach_cookie(self.as_ptr()) as u32) } unsafe { Ok(aya_bpf_bindings::helpers::bpf_get_attach_cookie(self.as_ptr()) as u32) }
} }
/// Access the spec_id using the `USDT_IP_TO_SPEC_ID` map
#[cfg(not(feature = "cookie"))] #[cfg(not(feature = "cookie"))]
#[inline(always)] #[inline(always)]
fn spec_id(&self) -> Result<u32, ()> { fn spec_id(&self) -> Result<u32, ()> {
@ -54,6 +58,10 @@ impl UsdtContext {
Ok(*spec) Ok(*spec)
} }
/// Returns the value of the USDT argument `n` as a u64.
///
/// This uses the USDT_SPEC_MAP to determine the correct specification to use in order
/// to read the value of argument `n` from the eBPF Context.
#[inline(always)] #[inline(always)]
pub fn arg(&self, n: usize) -> Result<u64, ()> { pub fn arg(&self, n: usize) -> Result<u64, ()> {
if n > USDT_MAX_ARG_COUNT { if n > USDT_MAX_ARG_COUNT {

Loading…
Cancel
Save