probe_rs_debug/
variable.rs

1use crate::{language::ProgrammingLanguage, unit_info::UnitInfo};
2
3use super::*;
4use gimli::{DebugInfoOffset, DwLang, UnitOffset};
5use itertools::Itertools;
6use probe_rs::RegisterValue;
7use std::ops::Range;
8
9/// Define the role that a variable plays in a Variant relationship. See section '5.7.10 Variant
10/// Entries' of the DWARF 5 specification
11#[derive(Debug, Clone, Eq, PartialEq, Default)]
12pub enum VariantRole {
13    /// A (parent) Variable that can have any number of Variant's as its value
14    VariantPart(u64),
15    /// A (child) Variable that defines one of many possible types to hold the current value of a
16    /// VariantPart.
17    Variant(u64),
18    /// This variable doesn't play a role in a Variant relationship
19    #[default]
20    NonVariant,
21}
22
23/// A [Variable] will have either a valid value, or some reason why a value could not be constructed.
24/// - If we encounter expected errors, they will be displayed to the user as defined below.
25/// - If we encounter unexpected errors, they will be treated as proper errors and will propagated
26///   to the calling process as an `Err()`
27#[derive(Clone, Debug, PartialEq, Eq, Default)]
28pub enum VariableValue {
29    /// A valid value of this variable
30    Valid(String),
31    /// Notify the user that we encountered a problem correctly resolving the variable.
32    /// - The variable will be visible to the user, as will the other field of the variable.
33    /// - The contained warning message will be displayed to the user.
34    /// - The debugger will not attempt to resolve additional fields or children of this variable.
35    Error(String),
36    /// The value has not been set. This could be because ...
37    /// - It is too early in the process to have discovered its value, or ...
38    /// - The variable cannot have a stored value, e.g. a `struct`. In this case, please use
39    ///   `Variable::get_value` to infer a human readable value from the value of the struct's fields.
40    #[default]
41    Empty,
42}
43
44impl std::fmt::Display for VariableValue {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        match self {
47            VariableValue::Valid(value) => value.fmt(f),
48            VariableValue::Error(error) => write!(f, "< {error} >"),
49            VariableValue::Empty => write!(
50                f,
51                "Value not set. Please use Variable::get_value() to infer a human readable variable value"
52            ),
53        }
54    }
55}
56
57impl VariableValue {
58    /// Returns `true` if the variable resolver did not encounter an error, `false` otherwise.
59    pub fn is_valid(&self) -> bool {
60        !matches!(self, VariableValue::Error(_))
61    }
62
63    /// Returns `true` if no value or error is present, `false` otherwise.
64    pub fn is_empty(&self) -> bool {
65        matches!(self, VariableValue::Empty)
66    }
67}
68
69/// The type of variable we have at hand.
70#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize)]
71pub enum VariableName {
72    /// Top-level variable for static variables, child of a stack frame variable,
73    /// and holds all the static scoped variables which are directly visible to the
74    /// compile unit of the frame.
75    StaticScopeRoot,
76    /// Top-level variable for registers, child of a stack frame variable.
77    RegistersRoot,
78    /// Top-level variable for local scoped variables, child of a stack frame variable.
79    LocalScopeRoot,
80    /// Artificial variable, without a name (e.g. enum discriminant)
81    Artifical,
82    /// Anonymous namespace
83    AnonymousNamespace,
84    /// A Namespace with a specific name
85    Namespace(String),
86    /// Variable with a specific name
87    Named(String),
88    /// Entry of an array or similar
89    Indexed(u64),
90    /// Variable with an unknown name
91    #[default]
92    Unknown,
93}
94
95impl std::fmt::Display for VariableName {
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        match self {
98            VariableName::StaticScopeRoot => write!(f, "Static Variable"),
99            VariableName::RegistersRoot => write!(f, "Platform Register"),
100            VariableName::LocalScopeRoot => write!(f, "Function Variable"),
101            VariableName::Artifical => write!(f, "<artifical>"),
102            VariableName::AnonymousNamespace => write!(f, "<anonymous_namespace>"),
103            VariableName::Namespace(name) => name.fmt(f),
104            VariableName::Named(name) => name.fmt(f),
105            VariableName::Indexed(index) => write!(f, "__{index}"),
106            VariableName::Unknown => write!(f, "<unknown>"),
107        }
108    }
109}
110
111/// Encode the nature of the Debug Information Entry in a way that we can resolve child nodes of a
112/// [Variable].
113///
114/// The rules for 'lazy loading'/deferred recursion of [Variable] children are described under each
115/// of the enum values.
116#[derive(Debug, PartialEq, Eq, Clone, Default)]
117pub enum VariableNodeType {
118    /// Use the `header_offset` and `type_offset` as direct references for recursing the variable
119    /// children. With the current implementation, the `type_offset` will point to a DIE with a tag
120    /// of `DW_TAG_structure_type`.
121    /// - Rule: For structured variables, we WILL NOT automatically expand their children, but we
122    ///   have enough information to expand it on demand. Except if they fall into one of the
123    ///   special cases handled by [VariableNodeType::RecurseToBaseType]
124    TypeOffset(DebugInfoOffset, UnitOffset),
125    /// Use the `header_offset` and `entries_offset` as direct references for recursing the variable
126    /// children.
127    /// - Rule: All top level variables in a [StackFrame] are automatically deferred, i.e
128    ///   [VariableName::LocalScopeRoot], [VariableName::RegistersRoot].
129    DirectLookup(DebugInfoOffset, UnitOffset),
130    /// Look up information from all compilation units. This is used to resolve static variables, so
131    /// when [`VariableName::StaticScopeRoot`] is used.
132    UnitsLookup,
133    /// Sometimes it doesn't make sense to recurse the children of a specific node type
134    /// - Rule: Pointers to `unit` datatypes WILL NOT BE resolved, because it doesn't make sense.
135    /// - Rule: Once we determine that a variable can not be recursed further, we update the
136    ///   variable_node_type to indicate that no further recursion is possible/required. This
137    ///   can be because the variable is a 'base' data type, or because there was some kind of
138    ///   error in processing the current node, so we don't want to incur cascading errors.
139    // TODO: Find code instances where we use magic values (e.g. u32::MAX) and replace with DoNotRecurse logic if appropriate.
140    DoNotRecurse,
141    /// Unless otherwise specified, always recurse the children of every node until we get to the
142    /// base data type.
143    /// - Rule: (Default) Unless it is prevented by any of the other rules, we always recurse the
144    ///   children of these variables.
145    /// - Rule: Certain structured variables (e.g. `&str`, `Some`, `Ok`, `Err`, etc.) are set to
146    ///   [VariableNodeType::RecurseToBaseType] to improve the debugger UX.
147    /// - Rule: Pointers to `const` variables WILL ALWAYS BE recursed, because they provide
148    ///   essential information, for example about the length of strings, or the size of
149    ///   arrays.
150    /// - Rule: Enumerated types WILL ALWAYS BE recursed, because we only ever want to see the
151    ///   'active' child as the value.
152    /// - Rule: For now, Array types WILL ALWAYS BE recursed. TODO: Evaluate if it is beneficial to
153    ///   defer these.
154    /// - Rule: For now, Union types WILL ALWAYS BE recursed. TODO: Evaluate if it is beneficial to
155    ///   defer these.
156    #[default]
157    RecurseToBaseType,
158}
159
160impl VariableNodeType {
161    /// Will return `true` if the `variable_node_type` value implies that the variable will be
162    /// 'lazy' resolved.
163    pub fn is_deferred(&self) -> bool {
164        match self {
165            VariableNodeType::TypeOffset(_, _)
166            | VariableNodeType::DirectLookup(_, _)
167            | VariableNodeType::UnitsLookup => true,
168            VariableNodeType::DoNotRecurse | VariableNodeType::RecurseToBaseType => false,
169        }
170    }
171}
172
173/// The starting bit (and direction) of a bit field type.
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
175pub enum BitOffset {
176    /// The bit offset is from the least significant bit.
177    FromLsb(u64),
178    /// The bit offset is from the most significant bit.
179    FromMsb(u64),
180}
181
182/// Bitfield information for a variable.
183#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
184pub struct Bitfield {
185    /// The starting bit (and direction) of a bit field type.
186    pub offset: BitOffset,
187    /// The length of the bit field.
188    pub length: u64,
189}
190
191impl Default for Bitfield {
192    fn default() -> Self {
193        Bitfield {
194            offset: BitOffset::FromLsb(0),
195            length: 0,
196        }
197    }
198}
199
200impl Bitfield {
201    /// Returns a Bitfield that has a FromLsb offset.
202    pub(crate) fn normalize(&self, byte_size: u64) -> Self {
203        let offset = self.offset(byte_size);
204        Bitfield {
205            offset: BitOffset::FromLsb(offset),
206            length: self.length,
207        }
208    }
209
210    pub(crate) fn offset(&self, byte_size: u64) -> u64 {
211        match self.offset {
212            BitOffset::FromLsb(offset) => offset,
213            BitOffset::FromMsb(offset) => byte_size * 8 - offset - self.length,
214        }
215    }
216
217    pub(crate) fn normalized_offset(&self) -> u64 {
218        match self.offset {
219            BitOffset::FromLsb(offset) => offset,
220            BitOffset::FromMsb(_) => unreachable!("Bitfield should have been normalized first"),
221        }
222    }
223
224    pub(crate) fn length(&self) -> u64 {
225        self.length
226    }
227
228    pub(crate) fn mask(&self) -> u128 {
229        (1 << self.length) - 1
230    }
231
232    pub(crate) fn extract(&self, value: u128) -> u128 {
233        let offset = self.normalized_offset();
234        let mask = self.mask();
235
236        (value >> offset) & mask
237    }
238
239    pub(crate) fn insert(&self, value: u128, new_value: u128) -> u128 {
240        let offset = self.normalized_offset();
241        let mask = self.mask();
242
243        let shifted_mask = mask << offset;
244        let new_value = (new_value & mask) << offset;
245        (value & !shifted_mask) | new_value
246    }
247}
248
249/// A modifier to a variable type. Currently only used to format the type name.
250#[derive(Debug, Clone, Eq, PartialEq, Serialize)]
251pub enum Modifier {
252    /// The type is declared as `volatile`.
253    Volatile,
254
255    /// The type is declared as `const`.
256    Const,
257
258    /// The type is declared as `restrict`.
259    Restrict,
260
261    /// The type is declared as `atomic`.
262    Atomic,
263
264    /// The type is an alias with the given name.
265    Typedef(String),
266}
267
268/// The variants of VariableType allows us to streamline the conditional logic that requires
269/// specific handling depending on the nature of the variable.
270#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
271pub enum VariableType {
272    /// A variable with a Rust base datatype.
273    Base(String),
274    /// The variable is a range of bits in a wider (integer) type.
275    Bitfield(Bitfield, Box<VariableType>),
276    /// A Rust struct.
277    Struct(String),
278    /// A Rust enum.
279    Enum(String),
280    /// Namespace refers to the path that qualifies a variable. e.g. "std::string" is the namespace
281    /// for the struct "String"
282    Namespace,
283    /// A Pointer is a variable that contains a reference to another variable, and the type of the
284    /// referenced variable may not be known until the reference has been resolved.
285    Pointer(Option<String>),
286    /// A Rust array.
287    Array {
288        /// The type name of the variable.
289        item_type_name: Box<VariableType>,
290        /// The number of entries in the array.
291        count: usize,
292    },
293    /// A type alias.
294    Modified(Modifier, Box<VariableType>),
295    /// When we are unable to determine the name of a variable.
296    #[default]
297    Unknown,
298    /// For infrequently used categories of variables that does not fall into any of the other
299    /// `VariableType` variants.
300    Other(String),
301}
302
303impl VariableType {
304    /// Get the inner type of a modified type.
305    pub fn inner(&self) -> &Self {
306        if let Self::Modified(_, ty) = self {
307            ty.inner()
308        } else {
309            self
310        }
311    }
312
313    /// Get the inner type of a modified type, stopping at typedef aliases.
314    fn skip_modifiers(&self) -> &Self {
315        match self {
316            Self::Modified(Modifier::Typedef(_), _) => self,
317            Self::Modified(_, ty) => ty.skip_modifiers(),
318            _ => self,
319        }
320    }
321
322    /// Is this variable of a Rust PhantomData marker type?
323    pub fn is_phantom_data(&self) -> bool {
324        match self {
325            VariableType::Struct(name) => name.starts_with("PhantomData"),
326            _ => false,
327        }
328    }
329
330    /// Is this variable an array?
331    pub fn is_array(&self) -> bool {
332        matches!(self, VariableType::Array { .. })
333    }
334
335    /// Returns the string representation of the variable type's kind.
336    pub fn kind(&self) -> &str {
337        match self {
338            VariableType::Base(_) => "base",
339            VariableType::Bitfield(..) => "bitfield",
340            VariableType::Struct(_) => "struct",
341            VariableType::Enum(_) => "enum",
342            VariableType::Namespace => "namespace",
343            VariableType::Pointer(_) => "pointer",
344            VariableType::Array { .. } => "array",
345            VariableType::Unknown => "unknown",
346            VariableType::Other(_) => "other",
347            VariableType::Modified(_, inner) => inner.kind(),
348        }
349    }
350
351    pub(crate) fn display_name(&self, language: &dyn ProgrammingLanguage) -> String {
352        match self {
353            VariableType::Modified(Modifier::Typedef(name), _) => name.clone(),
354            VariableType::Modified(modifier, ty) => {
355                language.modified_type_name(modifier, &ty.display_name(language))
356            }
357
358            VariableType::Array {
359                item_type_name,
360                count,
361            } => language.format_array_type(
362                // In case the compiler points at a modified item type (e.g. const), skip the
363                // modifier.
364                &item_type_name.skip_modifiers().display_name(language),
365                *count,
366            ),
367
368            VariableType::Bitfield(bitfield, name) => {
369                language.format_bitfield_type(&name.display_name(language), *bitfield)
370            }
371
372            _ => self.type_name(language),
373        }
374    }
375
376    /// Returns the type name after resolving aliases.
377    pub(crate) fn type_name(&self, language: &dyn ProgrammingLanguage) -> String {
378        let type_name = match self {
379            VariableType::Base(name)
380            | VariableType::Struct(name)
381            | VariableType::Enum(name)
382            | VariableType::Other(name) => Some(name.as_str()),
383
384            VariableType::Namespace => Some("namespace"),
385            VariableType::Unknown => None,
386
387            VariableType::Pointer(pointee) => {
388                // TODO: we should also carry the constness
389                return language.format_pointer_type(pointee.as_deref());
390            }
391
392            VariableType::Array {
393                item_type_name,
394                count,
395            } => return language.format_array_type(&item_type_name.type_name(language), *count),
396
397            VariableType::Bitfield(_, ty) | VariableType::Modified(_, ty) => {
398                return ty.type_name(language);
399            }
400        };
401
402        type_name.unwrap_or("<unknown>").to_string()
403    }
404}
405
406/// Location of a variable
407#[derive(Debug, Clone, PartialEq, Default)]
408pub enum VariableLocation {
409    /// Location of the variable is not known. This means that it has not been evaluated yet.
410    #[default]
411    Unknown,
412    /// The variable does not have a location currently, probably due to optimisations.
413    Unavailable,
414    /// The variable can be found in memory, at this address.
415    Address(u64),
416    /// The value of the variable is directly available.
417    Value,
418    /// The variable is stored in a register, and the value is read from there.
419    RegisterValue(RegisterValue),
420    /// There was an error evaluating the variable location.
421    Error(String),
422    /// Support for handling the location of this variable is not (yet) implemented.
423    Unsupported(String),
424}
425
426impl VariableLocation {
427    /// Return the memory address, if available. Otherwise an error is returned.
428    pub fn memory_address(&self) -> Result<u64, DebugError> {
429        match self {
430            VariableLocation::Address(address) => Ok(*address),
431            VariableLocation::RegisterValue(address) => match TryInto::<u64>::try_into(*address) {
432                Ok(address) => Ok(address),
433                Err(_) => Err(DebugError::WarnAndContinue {
434                    message: "Register value is not a valid address".to_string(),
435                }),
436            },
437            VariableLocation::Error(error) => Err(DebugError::WarnAndContinue {
438                message: error.clone(),
439            }),
440            other => Err(DebugError::WarnAndContinue {
441                message: format!("Variable does not have a memory location: location={other:?}"),
442            }),
443        }
444    }
445
446    /// Check if the location is valid, ie. not an error, unsupported, or unavailable.
447    pub fn valid(&self) -> bool {
448        match self {
449            VariableLocation::Address(_)
450            | VariableLocation::RegisterValue(_)
451            | VariableLocation::Value
452            | VariableLocation::Unknown => true,
453            _other => false,
454        }
455    }
456}
457
458impl std::fmt::Display for VariableLocation {
459    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
460        match self {
461            VariableLocation::Unknown => "<unknown value>".fmt(f),
462            VariableLocation::Unavailable => "<value not available>".fmt(f),
463            VariableLocation::Address(address) => {
464                write!(f, "{address:#010X}")
465            }
466            VariableLocation::RegisterValue(address) => match address {
467                RegisterValue::U32(value) => write!(f, "{value:#010X}"),
468                RegisterValue::U64(value) => write!(f, "{value:#018X}"),
469                RegisterValue::U128(value) => write!(f, "{value:#034X}"),
470            },
471            VariableLocation::Value => "<not applicable - statically stored value>".fmt(f),
472            VariableLocation::Error(error) => error.fmt(f),
473            VariableLocation::Unsupported(reason) => reason.fmt(f),
474        }
475    }
476}
477
478/// The `Variable` struct is used in conjunction with `VariableCache` to cache data about variables.
479///
480/// Any modifications to the `Variable` value will be transient (lost when it goes out of scope),
481/// unless it is updated through one of the available methods on `VariableCache`.
482#[derive(Debug, Clone, PartialEq)]
483pub struct Variable {
484    /// Every variable must have a unique key value assigned to it.
485    /// The value will be zero until it is stored in VariableCache, at which time its value will be
486    /// set to the same as the VariableCache::variable_cache_key
487    pub(super) variable_key: ObjectRef,
488    /// The offset to the variable's type information.
489    pub(crate) type_node_offset: Option<UnitOffset>,
490    /// Every variable must have a unique parent assigned to it when stored in the VariableCache.
491    pub parent_key: ObjectRef,
492    /// The variable name refers to the name of any of the types of values described in the [VariableCache]
493    pub name: VariableName,
494
495    /// Linkage name of the variable. Multiple variables with the same name could exist,
496    /// this is used to distinguish between them.
497    pub(crate) linkage_name: Option<String>,
498
499    /// Use `Variable::set_value()` and `Variable::get_value()` to correctly process this `value`
500    pub(super) value: VariableValue,
501    /// The source location of the declaration of this variable, if available.
502    pub source_location: Option<SourceLocation>,
503    /// Programming language of the defining compilation unit.
504    pub language: DwLang,
505
506    /// The name of the type of this variable.
507    pub type_name: VariableType,
508    /// For 'lazy loading' of certain variable types we have to determine if the variable recursion
509    /// should be deferred, and if so, how to resolve it when the request for further recursion
510    /// happens.
511    /// See [VariableNodeType] for more information.
512    pub variable_node_type: VariableNodeType,
513    /// The starting location/address in memory where this Variable's value is stored.
514    pub memory_location: VariableLocation,
515    /// The size of this variable in bytes.
516    pub byte_size: Option<u64>,
517    /// The role of this variable.
518    pub role: VariantRole,
519}
520
521impl Variable {
522    /// In most cases, Variables will be initialized with their ELF references so that we resolve
523    /// their data types and values on demand.
524    pub fn new(unit_info: Option<&UnitInfo>) -> Variable {
525        Variable {
526            language: unit_info
527                .map(|info| info.get_language())
528                .unwrap_or(gimli::DW_LANG_Rust),
529            type_node_offset: None,
530            variable_key: Default::default(),
531            parent_key: Default::default(),
532            name: Default::default(),
533            linkage_name: None,
534            value: Default::default(),
535            source_location: None,
536            type_name: Default::default(),
537            variable_node_type: Default::default(),
538            memory_location: Default::default(),
539            byte_size: None,
540            role: Default::default(),
541        }
542    }
543
544    /// Returns the readable name of the variable type.
545    pub fn type_name(&self) -> String {
546        self.type_name
547            .display_name(language::from_dwarf(self.language).as_ref())
548    }
549
550    /// Get a unique key for this variable.
551    pub fn variable_key(&self) -> ObjectRef {
552        self.variable_key
553    }
554
555    /// This ensures debug frontends can see the errors, but doesn't fail because of a single
556    /// variable not being able to decode correctly.
557    pub fn set_value(&mut self, new_value: VariableValue) {
558        // Allow some block when logic requires it.
559        if new_value.is_valid() || self.value.is_valid() {
560            // Simply overwrite existing value with a new valid one.
561            self.value = new_value;
562        } else {
563            // Concatenate the error messages ...
564            self.value = VariableValue::Error(format!("{} : {}", self.value, new_value));
565
566            // If the value is invalid, then make sure we don't propagate invalid memory location
567            // values.
568            self.memory_location =
569                VariableLocation::Error("Failed to resolve variable value".to_string());
570        }
571    }
572
573    /// Convert the [String] value into the appropriate memory format and update the target memory
574    /// with the new value.
575    /// Currently this only works for base data types. There is no provision in the MS DAP API to
576    /// catch this client side, so we can only respond with a 'gentle' error message if the user
577    /// attempts unsupported data types.
578    pub fn update_value(
579        &self,
580        memory: &mut impl MemoryInterface,
581        variable_cache: &mut VariableCache,
582        new_value: String,
583    ) -> Result<(), DebugError> {
584        let valid_value = self.is_valid();
585        let valid_type = self.type_name != VariableType::Unknown;
586        let valid_memory = self.memory_location.valid();
587        if !valid_value || !valid_type || !valid_memory {
588            // Insufficient data available.
589            Err(DebugError::Other(format!(
590                "Cannot update variable: {:?}, with supplied information (value={:?}, type={:?}, memory location={:#010x?}).",
591                self.name, self.value, self.type_name, self.memory_location
592            )))
593        } else {
594            // We have everything we need to update the variable value.
595            language::from_dwarf(self.language)
596                .update_variable(self, memory, &new_value)
597                .map_err(|error| DebugError::WarnAndContinue {
598                    message: format!("Invalid data value={new_value:?}: {error}"),
599                })?;
600
601            // Now update the cache with the new value for this variable.
602            let mut cache_variable = self.clone();
603            cache_variable.value = VariableValue::Valid(new_value);
604            cache_variable.extract_value(memory, variable_cache);
605            variable_cache.update_variable(&cache_variable)?;
606            Ok(())
607        }
608    }
609
610    /// Implementing get_value(), because Variable.value has to be private (a requirement of
611    /// updating the value without overriding earlier values ... see set_value()).
612    pub fn to_string(&self, variable_cache: &VariableCache) -> String {
613        // Allow for chained `if let` without complaining
614        if !self.value.is_empty() {
615            // The `value` for this `Variable` is non empty because either
616            // - It is base data type for which a value was determined based on the core runtime
617            // - We encountered an error somewhere, so report it to the user
618            return format!("{}", self.value);
619        }
620
621        if matches!(
622            self.name,
623            VariableName::AnonymousNamespace | VariableName::Namespace(_)
624        ) {
625            // Namespaces do not have values
626            return String::new();
627        }
628
629        // We need to construct a 'human readable' value using `fmt::Display` to represent the
630        // values of complex types and pointers.
631        if variable_cache.has_children(self) {
632            self.formatted_variable_value(variable_cache, 0, false)
633                .unwrap_or_default()
634        } else if self.type_name == VariableType::Unknown || !self.memory_location.valid() {
635            if self.variable_node_type.is_deferred() {
636                // When we will do a lazy-load of variable children, and they have not yet been
637                // requested by the user, just display the type_name as the value
638                self.type_name()
639            } else if let VariableLocation::Error(ref error) = self.memory_location {
640                error.clone()
641            } else {
642                // This condition should only be true for intermediate nodes
643                // from DWARF. These should not show up in the final
644                // `VariableCache`. If a user sees this error, then there is
645                // a logic problem in the stack unwind
646                "Error: This is a bug! Attempted to evaluate a Variable with no type or no memory location".to_string()
647            }
648        } else if matches!(self.type_name, VariableType::Struct(ref name) if name == "None") {
649            "None".to_string()
650        } else if matches!(self.type_name, VariableType::Array { count: 0, .. }) {
651            self.formatted_variable_value(variable_cache, 0, false)
652                .unwrap_or_default()
653        } else {
654            format!(
655                "Unimplemented: Get value of type {:?} of ({:?} bytes) at location {}",
656                self.type_name, self.byte_size, self.memory_location
657            )
658        }
659    }
660
661    /// Evaluate the variable's result if possible and set self.value, or else set self.value as the error String.
662    pub fn extract_value(
663        &mut self,
664        memory: &mut dyn MemoryInterface,
665        variable_cache: &VariableCache,
666    ) {
667        if let VariableValue::Error(_) = self.value {
668            // Nothing more to do ...
669            return;
670        }
671
672        let empty = self.value.is_empty();
673        // The value was set explicitly, so just leave it as is, or it was an error, so don't attempt
674        // anything else
675        let valid = self.memory_location.valid();
676        // This may just be that we are early on in the process of `Variable` evaluation
677        let unknown = self.type_name.inner() == &VariableType::Unknown;
678
679        if !empty || !valid || unknown {
680            return;
681        }
682
683        if self.variable_node_type.is_deferred()
684            || matches!(self.type_name, VariableType::Pointer(_))
685        {
686            // And we have not previously assigned the value, then assign the type and address as
687            // the value.
688            self.value =
689                VariableValue::Valid(format!("{} @ {}", self.type_name(), self.memory_location));
690            return;
691        }
692
693        tracing::trace!(
694            "Extracting value for {:?}, type={:?}",
695            self.name,
696            self.type_name
697        );
698
699        self.value =
700            language::from_dwarf(self.language).read_variable_value(self, memory, variable_cache);
701    }
702
703    /// The variable is considered to be an 'indexed' variable if the name starts with two
704    /// underscores followed by a number. e.g. "__1".
705    // TODO: Consider replacing this logic with `std::str::pattern::Pattern` when that API stabilizes
706    pub fn is_indexed(&self) -> bool {
707        match &self.name {
708            VariableName::Named(name) => {
709                name.starts_with("__")
710                    && name
711                        .find(char::is_numeric)
712                        .is_some_and(|zero_based_position| zero_based_position == 2)
713            }
714            // Other kind of variables are never indexed
715            _ => false,
716        }
717    }
718
719    /// Returns `true` if the variable has a name, `false` otherwise.
720    pub fn is_named(&self) -> bool {
721        matches!(&self.name, VariableName::Named(_))
722    }
723
724    /// `true` if the Variable has a valid value, or an empty value.
725    /// `false` if the Variable has a VariableValue::Error(_) value
726    pub fn is_valid(&self) -> bool {
727        self.value.is_valid()
728    }
729
730    /// Format the variable.
731    fn formatted_variable_value(
732        &self,
733        variable_cache: &VariableCache,
734        indentation: usize,
735        show_name: bool,
736    ) -> Option<String> {
737        let type_name = self.type_name();
738
739        if !self.value.is_empty() {
740            // This is the end of the recursion where we already have a scalar
741            // value for a variable and we can just move it up.
742            let line_start = line_indent_string(indentation);
743            return Some(if show_name {
744                format!("{line_start}{}: {} = {}", self.name, type_name, self.value)
745            } else {
746                format!("{line_start}{}", self.value)
747            });
748        } else if matches!(
749            self.name,
750            VariableName::AnonymousNamespace | VariableName::Namespace(_)
751        ) {
752            // Namespaces do not have values, so we report no value up.
753            // This will alow us to filter it out when we concatenate children.
754            return None;
755        }
756
757        // Infer a human readable value using the available children of this variable.
758        let children = &mut variable_cache.get_children(self.variable_key);
759        let first_child = children.clone().next();
760
761        // Make sure we can safely unwrap() children.
762        Some(match self.type_name.inner() {
763            VariableType::Pointer(_) => {
764                format_pointer_value(variable_cache, indentation, first_child)
765            }
766            VariableType::Array { .. } => {
767                format_array_value(variable_cache, indentation, children, &type_name)
768            }
769            VariableType::Struct(name) if name == "Some" || name == "Ok" || name == "Err" => {
770                format_struct_value(variable_cache, indentation, children, &type_name)
771            }
772            _ if first_child.is_none() => {
773                // This is a struct with no children, so just print the type name.
774                // This is for example the None value of an Option or the empty type ().
775                type_name
776            }
777            _ if matches!(
778                self.name,
779                VariableName::StaticScopeRoot
780                    | VariableName::LocalScopeRoot
781                    | VariableName::RegistersRoot
782            ) =>
783            {
784                format_root_value(variable_cache, indentation, children, &type_name)
785            }
786            _ => format_default_value(
787                variable_cache,
788                indentation,
789                &self.name,
790                children,
791                &type_name,
792                show_name,
793            ),
794        })
795    }
796
797    /// Calculate the memory range that contains the value of this variable.
798    ///
799    /// If the location and/or byte size is not known, then return None.
800    /// Note: We don't do any validation of the memory range here and leave it
801    /// up to the caller to validate the memory ranges before attempting to read
802    /// them.
803    pub fn memory_range(&self) -> Option<Range<u64>> {
804        let VariableLocation::Address(address) = self.memory_location else {
805            return None;
806        };
807
808        self.byte_size.map(|byte_size| {
809            if byte_size == 0 {
810                address..address + 4
811            } else {
812                address..(address + byte_size)
813            }
814        })
815    }
816}
817
818/// Format a pointer value
819///
820/// Formats the pointed to value and potential subsequent children as well.
821fn format_pointer_value(
822    variable_cache: &VariableCache,
823    indentation: usize,
824    first_child: Option<&Variable>,
825) -> String {
826    let line_start = line_indent_string(indentation);
827
828    let value = if let Some(first_child) = first_child {
829        first_child
830            .formatted_variable_value(variable_cache, indentation + 1, true)
831            .expect("a child. This is a bug. Please report it.")
832    } else {
833        "Unable to resolve referenced variable value".to_string()
834    };
835
836    format!("{line_start}{value}")
837}
838
839/// Format any array like value.
840///
841/// Recursively formats all child values.
842fn format_array_value<'a>(
843    variable_cache: &VariableCache,
844    indentation: usize,
845    children: &mut (impl Iterator<Item = &'a Variable> + Clone),
846    type_name: &str,
847) -> String {
848    let line_start = line_indent_string(indentation);
849
850    // Limit arrays to 10 elements
851    const ARRAY_MAX_LENGTH: usize = 10;
852
853    // If we at least ARRAY_MAX_LENGTH + 2 items in the iterator, cap at ARRAY_MAX_LENGTH.
854    // If we have less, cap at the actual number of items.
855    // This helps us to never write "and 1 more" with the reasoning that the space used for this
856    // text, can be used for printing that one item.
857    let count = children.clone().count();
858    let take = if count > ARRAY_MAX_LENGTH + 1 {
859        ARRAY_MAX_LENGTH
860    } else {
861        count
862    };
863
864    let children_values = children
865        .by_ref()
866        .take(take)
867        .filter_map(|child| child.formatted_variable_value(variable_cache, indentation + 1, false))
868        .join(",");
869
870    let remainder = if count > ARRAY_MAX_LENGTH + 1 {
871        format!(",\n{line_start}\t... and {} more", count - take)
872    } else {
873        String::new()
874    };
875
876    format!("{line_start}{type_name} = [{children_values}{remainder}{line_start}]")
877}
878
879/// Format any struct like value .
880///
881/// Recursively formats all child values.
882fn format_struct_value<'a>(
883    variable_cache: &VariableCache,
884    indentation: usize,
885    children: &mut (impl Iterator<Item = &'a Variable> + Clone),
886    type_name: &str,
887) -> String {
888    let line_start = line_indent_string(indentation);
889
890    // FIXME: this is not hit by any of the unwind tests, which is weird because
891    // some of them contain `Some` structs.
892    // Handle special structure types like the variant values of `Option<>` and `Result<>`
893    let children_values = format_children_values(variable_cache, indentation, children, false);
894
895    format!("{line_start}{type_name} = ({children_values})")
896}
897
898/// Format any root value.
899///
900/// Recursively formats all child values.
901fn format_root_value<'a>(
902    variable_cache: &VariableCache,
903    indentation: usize,
904    children: &mut (impl Iterator<Item = &'a Variable> + Clone),
905    type_name: &str,
906) -> String {
907    let line_start = line_indent_string(indentation);
908
909    let children_values = format_children_values(variable_cache, indentation, children, true);
910    format!("{line_start}{type_name} {{{children_values}{line_start}}}")
911}
912
913/// Format any value that has no type that requires special handling.
914///
915/// Recursively formats all child values.
916fn format_default_value<'a>(
917    variable_cache: &VariableCache,
918    indentation: usize,
919    name: &VariableName,
920    children: &mut (impl Iterator<Item = &'a Variable> + Clone),
921    type_name: &String,
922    show_name: bool,
923) -> String {
924    let line_start = line_indent_string(indentation);
925
926    // Find the first child of the structure if it exists.
927    let child = children.clone().find(|v| v.is_named());
928
929    // If we do not have children, exit early because we cannot print more specifics (children)
930    // of this variable type. We instead print the empty type symbol.
931    let Some(child) = child else {
932        return "()".to_string();
933    };
934
935    let child_type_name = child.type_name();
936    if child.is_indexed() {
937        // Treat this structure as a tuple
938        let children_values = format_children_values(variable_cache, indentation, children, false);
939        let name = if show_name {
940            format!("{name}: {type_name}({child_type_name}) = ")
941        } else {
942            String::new()
943        };
944        format!("{line_start}{name}{type_name}({children_values}{line_start})")
945    } else {
946        // Treat this structure as a `struct`
947        let children_values = format_children_values(variable_cache, indentation, children, true);
948        let name = if show_name {
949            format!("{name}: {type_name} = ")
950        } else {
951            String::new()
952        };
953        format!("{line_start}{name}{type_name} {{{children_values}{line_start}}}")
954    }
955}
956
957/// Concatenate all children values with a comma.
958fn format_children_values<'a>(
959    variable_cache: &VariableCache,
960    indentation: usize,
961    children: &mut (impl Iterator<Item = &'a Variable> + Clone),
962    show_name: bool,
963) -> String {
964    children
965        .filter_map(|child| {
966            child.formatted_variable_value(variable_cache, indentation + 1, show_name)
967        })
968        .join(",")
969}
970
971/// Genarate a string that indents the line exactly the right amount.
972/// Includes a newline at the start if the indentation is bigger than 0.
973fn line_indent_string(indentation: usize) -> String {
974    let line_feed = if indentation == 0 { "" } else { "\n" };
975    format!("{line_feed}{:\t<indentation$}", "")
976}