stackwise-core 0.3.1

Artifact-first Rust stack analysis engine used by Stackwise
Documentation
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

pub const SCHEMA_VERSION: &str = "0.1.0";

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct StackwiseReport {
    pub schema_version: String,
    pub generator: GeneratorInfo,
    pub artifact: ArtifactInfo,
    pub build: Option<BuildInfo>,
    pub summary: Summary,
    pub symbols: Vec<SymbolReport>,
    pub edges: Vec<EdgeReport>,
    pub groups: Vec<GroupReport>,
    pub diagnostics: Vec<Diagnostic>,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct GeneratorInfo {
    pub name: String,
    pub version: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct ArtifactInfo {
    pub path: String,
    pub file_name: String,
    pub format: ObjectFormat,
    pub architecture: String,
    pub pointer_width: Option<u8>,
    pub size_bytes: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct BuildInfo {
    pub workspace_root: Option<String>,
    pub package: Option<String>,
    pub profile: Option<String>,
    pub target: Option<String>,
    pub features: Vec<String>,
    pub exact_mode: ExactMode,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ExactMode {
    Off,
    Auto,
    Required,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Summary {
    pub symbol_count: usize,
    pub edge_count: usize,
    pub known_frame_count: usize,
    pub unknown_frame_count: usize,
    pub recursive_symbol_count: usize,
    pub indirect_edge_count: usize,
    pub max_own_frame: Option<SymbolMetric>,
    pub max_worst_path: Option<SymbolMetric>,
    pub confidence: Confidence,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct SymbolMetric {
    pub symbol_id: u32,
    pub bytes: u64,
    pub demangled: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct SymbolReport {
    pub id: u32,
    pub name: String,
    pub demangled: String,
    pub crate_name: Option<String>,
    pub module_path: Vec<String>,
    pub address: u64,
    pub size_bytes: Option<u64>,
    pub source_location: Option<SourceLocation>,
    pub object_format: ObjectFormat,
    pub own_frame: FrameInfo,
    pub worst_path: WorstPathInfo,
    pub confidence: Confidence,
    pub evidence: Vec<Evidence>,
    pub unresolved_reasons: Vec<UnresolvedReason>,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct FrameInfo {
    pub bytes: Option<u64>,
    pub status: FrameStatus,
    pub evidence_source: EvidenceSource,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum FrameStatus {
    Known,
    Unknown,
    Dynamic,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct WorstPathInfo {
    pub bytes: Option<u64>,
    pub status: UpperBoundStatus,
    pub path: Vec<u32>,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum UpperBoundStatus {
    Known,
    Unknown,
    Recursive,
    Dynamic,
    Indirect,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Evidence {
    pub source: EvidenceSource,
    pub confidence: Confidence,
    pub note: String,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum EvidenceSource {
    ElfStackSizes,
    PeUnwind,
    MachOUnwind,
    PrologueDisassembly,
    SymbolOnly,
    Unknown,
}

#[derive(
    Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq, PartialOrd, Ord,
)]
#[serde(rename_all = "snake_case")]
pub enum Confidence {
    Exact,
    High,
    Medium,
    Low,
    Unknown,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct EdgeReport {
    pub caller: u32,
    pub callee: Option<u32>,
    pub target_address: Option<u64>,
    pub kind: EdgeKind,
    pub confidence: Confidence,
}

#[derive(
    Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq, PartialOrd, Ord,
)]
#[serde(rename_all = "snake_case")]
pub enum EdgeKind {
    DirectCall,
    TailCall,
    IndirectCall,
    ExternalCall,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct GroupReport {
    pub id: u32,
    pub name: String,
    pub parent: Option<u32>,
    pub symbol_ids: Vec<u32>,
    pub own_frame_sum: Option<u64>,
    pub worst_path_max: Option<u64>,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct SourceLocation {
    pub file: String,
    pub line: Option<u32>,
    pub column: Option<u32>,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Diagnostic {
    pub level: DiagnosticLevel,
    pub code: String,
    pub message: String,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum DiagnosticLevel {
    Info,
    Warning,
    Error,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ObjectFormat {
    Elf,
    PeCoff,
    MachO,
    Wasm,
    Unknown,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum UnresolvedReason {
    MissingStackEvidence,
    DynamicStackAllocation,
    RecursiveCycle,
    IndirectCall,
    ExternalCall,
    UnsupportedObjectFormat,
    StrippedSymbols,
}