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 pub linkage_name: Option<String>,
152 pub address: Option<u64>,
154}
155
156impl<ADDR: funty::Integral> Variable<ADDR> {
157 pub fn display(&self, theme: Theme) -> String {
158 let mut kind_text = self.kind.to_string();
159 if !kind_text.is_empty() {
160 kind_text = theme.color_info(format!("({kind_text}) ")).to_string();
161 }
162
163 let mut location_text = self.location.to_string();
164 if !location_text.is_empty() {
165 location_text = format!("at {}", theme.color_url(location_text));
166 }
167
168 format!(
169 "{}{}: {} = {} ({})",
170 kind_text,
171 theme.color_variable_name(&self.name),
172 theme.color_type_name(&self.type_value.root().data().variable_type.name),
173 render_type_value_tree(&self.type_value, theme),
174 location_text,
175 )
176 }
177}
178
179#[derive(Debug, Clone)]
180pub enum VariableLocationResult {
181 NoLocationAttribute,
183 LocationListNotFound,
185 NoLocationFound,
187 LocationEvaluationStepNotImplemented(Rc<EvaluationResult<DefaultReader>>),
189 LocationsFound(Vec<Piece<DefaultReader, usize>>),
191}
192
193#[derive(Debug, Clone, Copy, Default)]
195pub struct VariableKind {
196 pub zero_sized: bool,
198 pub inlined: bool,
200 pub parameter: bool,
202}
203
204impl Display for VariableKind {
205 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206 let mut elements = vec![];
207
208 if self.zero_sized {
209 elements.push("zero-sized");
210 }
211 if self.inlined {
212 elements.push("inlined");
213 }
214 if self.parameter {
215 elements.push("parameter");
216 }
217
218 write!(f, "{}", elements.join(" "))
219 }
220}