#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Availability {
Available,
PartiallyAvailable,
OptimizedOut,
NotInScope,
Unsupported(UnsupportedReason),
Requires(RuntimeRequirement),
Ambiguous(AmbiguityReason),
}
impl Availability {
pub fn is_available(&self) -> bool {
matches!(self, Self::Available | Self::PartiallyAvailable)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UnsupportedReason {
DwarfOp { op: String },
ExpressionShape { detail: String },
TypeLayout { detail: String },
AddressClass { detail: String },
RegisterMapping { dwarf_reg: u16 },
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RuntimeRequirement {
CallerFrame,
SleepableUprobe,
UserMemoryRead,
DwarfCfiRecovery,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AmbiguityReason {
InlineContext { detail: String },
VariableDeclaration { detail: String },
TypeResolution { detail: String },
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Provenance {
DirectDie,
AbstractOrigin,
Specification,
LocationList,
CallSite,
Cfi,
Synthesized { detail: String },
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DebugInfoSource {
Embedded { path: String },
Explicit { path: String },
Debuglink { path: String },
Debuginfod { path: String },
Missing,
}
impl DebugInfoSource {
pub fn kind_label(&self) -> &'static str {
match self {
Self::Embedded { .. } => "embedded",
Self::Explicit { .. } => "explicit",
Self::Debuglink { .. } => "debuglink",
Self::Debuginfod { .. } => "debuginfod",
Self::Missing => "missing",
}
}
pub fn display_path(&self) -> Option<&str> {
match self {
Self::Embedded { path }
| Self::Explicit { path }
| Self::Debuglink { path }
| Self::Debuginfod { path } => Some(path),
Self::Missing => None,
}
}
pub fn summary(&self) -> String {
match self.display_path() {
Some(path) => format!("{} ({path})", self.kind_label()),
None => self.kind_label().to_string(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RuntimeCapabilities {
pub regular_uprobe: bool,
pub sleepable_uprobe: bool,
pub uprobe_multi: bool,
pub copy_from_user_task: bool,
pub max_bpf_stack_bytes: usize,
pub bounded_loops: bool,
pub arch: TargetArch,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetArch {
X86_64,
Aarch64,
Unknown,
}
impl TargetArch {
pub fn current() -> Self {
if cfg!(target_arch = "x86_64") {
Self::X86_64
} else if cfg!(target_arch = "aarch64") {
Self::Aarch64
} else {
Self::Unknown
}
}
}
impl Default for RuntimeCapabilities {
fn default() -> Self {
Self {
regular_uprobe: true,
sleepable_uprobe: false,
uprobe_multi: false,
copy_from_user_task: false,
max_bpf_stack_bytes: 512,
bounded_loops: true,
arch: TargetArch::current(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HelperMode {
NoUserMemoryRead,
ProbeReadUser,
CopyFromUserTask,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VerifierRisk {
Low,
RequiresBoundedLoops,
StackBudgetExceeded { estimated: usize, max: usize },
Unsupported { reason: String },
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{PieceLocation, VariableLocation};
#[test]
fn optimized_location_is_unavailable() {
assert_eq!(
Availability::from_variable_location(&VariableLocation::OptimizedOut),
Availability::OptimizedOut
);
}
#[test]
fn mixed_composite_location_is_partially_available() {
let location = VariableLocation::Pieces(vec![
PieceLocation {
location: Box::new(VariableLocation::RegisterValue { dwarf_reg: 0 }),
bit_size: 32,
bit_offset: 0,
},
PieceLocation {
location: Box::new(VariableLocation::OptimizedOut),
bit_size: 32,
bit_offset: 32,
},
]);
assert_eq!(
Availability::from_variable_location(&location),
Availability::PartiallyAvailable
);
}
}