1#![doc = include_str!("../README.md")]
2use render_colors::{Theme, ThemeColors};
5pub use stackdump_core;
6
7use crate::type_value_tree::variable_type::Archetype;
8use gimli::{EndianReader, EvaluationResult, Piece, RunTimeEndian};
9use std::{
10 fmt::{Debug, Display},
11 rc::Rc,
12};
13use type_value_tree::{rendering::render_type_value_tree, TypeValueTree};
14
15pub mod error;
16mod gimli_extensions;
17pub mod platform;
18pub mod render_colors;
19pub mod type_value_tree;
20mod variables;
21
22type DefaultReader = EndianReader<RunTimeEndian, Rc<[u8]>>;
23
24#[derive(Debug, Clone, Default)]
26pub struct Location {
27 pub file: Option<String>,
29 pub line: Option<u64>,
31 pub column: Option<u64>,
33}
34
35impl Display for Location {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 if let Some(file) = self.file.clone() {
38 write!(f, "{}", file)?;
39 if let Some(line) = self.line {
40 write!(f, ":{}", line)?;
41 if let Some(column) = self.column {
42 write!(f, ":{}", column)?;
43 }
44 }
45 }
46
47 Ok(())
48 }
49}
50
51#[derive(Debug, Clone)]
54pub struct Frame<ADDR: funty::Integral> {
55 pub function: String,
57 pub location: Location,
59 pub frame_type: FrameType,
61 pub variables: Vec<Variable<ADDR>>,
63}
64
65impl<ADDR: funty::Integral> Frame<ADDR> {
66 pub fn display(
72 &self,
73 show_parameters: bool,
74 show_inlined_vars: bool,
75 show_zero_sized_vars: bool,
76 theme: Theme,
77 ) -> String {
78 use std::fmt::Write;
79
80 let mut display = String::new();
81
82 writeln!(
83 display,
84 "{} ({})",
85 theme.color_function(&self.function),
86 theme.color_info(&self.frame_type)
87 )
88 .unwrap();
89
90 let location_text = self.location.to_string();
91 if !location_text.is_empty() {
92 writeln!(display, " at {}", theme.color_url(location_text)).unwrap();
93 }
94
95 let filtered_variables = self.variables.iter().filter(|v| {
96 (show_inlined_vars || !v.kind.inlined)
97 && (show_zero_sized_vars || !v.kind.zero_sized)
98 && (show_parameters || !v.kind.parameter)
99 && v.type_value.data().variable_type.archetype != Archetype::ObjectMemberPointer
101 });
102 if filtered_variables.clone().count() > 0 {
103 writeln!(display, " variables:").unwrap();
104 for variable in filtered_variables {
105 writeln!(display, " {}", variable.display(theme)).unwrap();
106 }
107 }
108
109 display
110 }
111}
112
113#[derive(Debug, Clone)]
115pub enum FrameType {
116 Function,
118 InlineFunction,
120 Exception,
122 Corrupted(String),
124 Static,
126}
127
128impl Display for FrameType {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 match self {
131 FrameType::Function => write!(f, "Function"),
132 FrameType::InlineFunction => write!(f, "Inline Function"),
133 FrameType::Exception => write!(f, "Exception"),
134 FrameType::Corrupted(reason) => write!(f, "Corrupted: \"{reason}\""),
135 FrameType::Static => write!(f, "Static"),
136 }
137 }
138}
139
140#[derive(Debug, Clone)]
142pub struct Variable<ADDR: funty::Integral> {
143 pub name: String,
145 pub kind: VariableKind,
147 pub type_value: TypeValueTree<ADDR>,
148 pub location: Location,
150}
151
152impl<ADDR: funty::Integral> Variable<ADDR> {
153 pub fn display(&self, theme: Theme) -> String {
154 let mut kind_text = self.kind.to_string();
155 if !kind_text.is_empty() {
156 kind_text = theme.color_info(format!("({}) ", kind_text)).to_string();
157 }
158
159 let mut location_text = self.location.to_string();
160 if !location_text.is_empty() {
161 location_text = format!("at {}", theme.color_url(location_text));
162 }
163
164 format!(
165 "{}{}: {} = {} ({})",
166 kind_text,
167 theme.color_variable_name(&self.name),
168 theme.color_type_name(&self.type_value.root().data().variable_type.name),
169 render_type_value_tree(&self.type_value, theme),
170 location_text,
171 )
172 }
173}
174
175#[derive(Debug, Clone)]
176pub enum VariableLocationResult {
177 NoLocationAttribute,
179 LocationListNotFound,
181 NoLocationFound,
183 LocationEvaluationStepNotImplemented(Rc<EvaluationResult<DefaultReader>>),
185 LocationsFound(Vec<Piece<DefaultReader, usize>>),
187}
188
189#[derive(Debug, Clone, Copy, Default)]
191pub struct VariableKind {
192 pub zero_sized: bool,
194 pub inlined: bool,
196 pub parameter: bool,
198}
199
200impl Display for VariableKind {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 let mut elements = vec![];
203
204 if self.zero_sized {
205 elements.push("zero-sized");
206 }
207 if self.inlined {
208 elements.push("inlined");
209 }
210 if self.parameter {
211 elements.push("parameter");
212 }
213
214 write!(f, "{}", elements.join(" "))
215 }
216}