1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4pub const SCHEMA_VERSION: &str = "0.1.0";
5
6#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
7pub struct StackwiseReport {
8 pub schema_version: String,
9 pub generator: GeneratorInfo,
10 pub artifact: ArtifactInfo,
11 pub build: Option<BuildInfo>,
12 pub summary: Summary,
13 pub symbols: Vec<SymbolReport>,
14 pub edges: Vec<EdgeReport>,
15 pub groups: Vec<GroupReport>,
16 pub diagnostics: Vec<Diagnostic>,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
20pub struct GeneratorInfo {
21 pub name: String,
22 pub version: String,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
26pub struct ArtifactInfo {
27 pub path: String,
28 pub file_name: String,
29 pub format: ObjectFormat,
30 pub architecture: String,
31 pub pointer_width: Option<u8>,
32 pub size_bytes: u64,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
36pub struct BuildInfo {
37 pub workspace_root: Option<String>,
38 pub package: Option<String>,
39 pub profile: Option<String>,
40 pub target: Option<String>,
41 pub features: Vec<String>,
42 pub exact_mode: ExactMode,
43}
44
45#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
46#[serde(rename_all = "snake_case")]
47pub enum ExactMode {
48 Off,
49 Auto,
50 Required,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
54pub struct Summary {
55 pub symbol_count: usize,
56 pub edge_count: usize,
57 pub known_frame_count: usize,
58 pub unknown_frame_count: usize,
59 pub recursive_symbol_count: usize,
60 pub indirect_edge_count: usize,
61 pub max_own_frame: Option<SymbolMetric>,
62 pub max_worst_path: Option<SymbolMetric>,
63 pub confidence: Confidence,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
67pub struct SymbolMetric {
68 pub symbol_id: u32,
69 pub bytes: u64,
70 pub demangled: String,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
74pub struct SymbolReport {
75 pub id: u32,
76 pub name: String,
77 pub demangled: String,
78 pub crate_name: Option<String>,
79 pub module_path: Vec<String>,
80 pub address: u64,
81 pub size_bytes: Option<u64>,
82 pub source_location: Option<SourceLocation>,
83 pub object_format: ObjectFormat,
84 pub own_frame: FrameInfo,
85 pub worst_path: WorstPathInfo,
86 pub confidence: Confidence,
87 pub evidence: Vec<Evidence>,
88 pub unresolved_reasons: Vec<UnresolvedReason>,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
92pub struct FrameInfo {
93 pub bytes: Option<u64>,
94 pub status: FrameStatus,
95 pub evidence_source: EvidenceSource,
96}
97
98#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
99#[serde(rename_all = "snake_case")]
100pub enum FrameStatus {
101 Known,
102 Unknown,
103 Dynamic,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
107pub struct WorstPathInfo {
108 pub bytes: Option<u64>,
109 pub status: UpperBoundStatus,
110 pub path: Vec<u32>,
111}
112
113#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
114#[serde(rename_all = "snake_case")]
115pub enum UpperBoundStatus {
116 Known,
117 Unknown,
118 Recursive,
119 Dynamic,
120 Indirect,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
124pub struct Evidence {
125 pub source: EvidenceSource,
126 pub confidence: Confidence,
127 pub note: String,
128}
129
130#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
131#[serde(rename_all = "snake_case")]
132pub enum EvidenceSource {
133 ElfStackSizes,
134 PeUnwind,
135 MachOUnwind,
136 PrologueDisassembly,
137 SymbolOnly,
138 Unknown,
139}
140
141#[derive(
142 Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq, PartialOrd, Ord,
143)]
144#[serde(rename_all = "snake_case")]
145pub enum Confidence {
146 Exact,
147 High,
148 Medium,
149 Low,
150 Unknown,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
154pub struct EdgeReport {
155 pub caller: u32,
156 pub callee: Option<u32>,
157 pub target_address: Option<u64>,
158 pub kind: EdgeKind,
159 pub confidence: Confidence,
160}
161
162#[derive(
163 Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq, PartialOrd, Ord,
164)]
165#[serde(rename_all = "snake_case")]
166pub enum EdgeKind {
167 DirectCall,
168 TailCall,
169 IndirectCall,
170 ExternalCall,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
174pub struct GroupReport {
175 pub id: u32,
176 pub name: String,
177 pub parent: Option<u32>,
178 pub symbol_ids: Vec<u32>,
179 pub own_frame_sum: Option<u64>,
180 pub worst_path_max: Option<u64>,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
184pub struct SourceLocation {
185 pub file: String,
186 pub line: Option<u32>,
187 pub column: Option<u32>,
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
191pub struct Diagnostic {
192 pub level: DiagnosticLevel,
193 pub code: String,
194 pub message: String,
195}
196
197#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
198#[serde(rename_all = "snake_case")]
199pub enum DiagnosticLevel {
200 Info,
201 Warning,
202 Error,
203}
204
205#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
206#[serde(rename_all = "snake_case")]
207pub enum ObjectFormat {
208 Elf,
209 PeCoff,
210 MachO,
211 Wasm,
212 Unknown,
213}
214
215#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
216#[serde(rename_all = "snake_case")]
217pub enum UnresolvedReason {
218 MissingStackEvidence,
219 DynamicStackAllocation,
220 RecursiveCycle,
221 IndirectCall,
222 ExternalCall,
223 UnsupportedObjectFormat,
224 StrippedSymbols,
225}