1use super::*;
2use crate::{stack_frame::StackFrameInfo, unit_info::UnitInfo};
3use gimli::UnitOffset;
4use probe_rs::Error;
5use probe_rs_target::MemoryRange;
6use serde::{Serialize, Serializer};
7use std::{
8 collections::{BTreeMap, btree_map::Entry},
9 ops::Range,
10};
11
12#[derive(Debug, Clone, PartialEq)]
14pub struct VariableCache {
15 root_variable_key: ObjectRef,
16
17 variable_hash_map: BTreeMap<ObjectRef, Variable>,
18}
19
20impl Serialize for VariableCache {
21 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
22 where
23 S: Serializer,
24 {
25 use serde::ser::SerializeStruct;
26
27 #[derive(Serialize)]
29 struct VariableTreeNode<'c> {
30 name: &'c VariableName,
31 type_name: &'c VariableType,
32 value: String,
34
35 #[serde(skip_serializing_if = "Option::is_none")]
36 source_location: Option<SourceLocation>,
37 #[serde(skip_serializing_if = "Vec::is_empty")]
39 children: Vec<VariableTreeNode<'c>>,
40 }
41
42 fn recurse_cache(variable_cache: &VariableCache) -> VariableTreeNode<'_> {
43 let root_node = variable_cache.root_variable();
44
45 VariableTreeNode {
46 name: &root_node.name,
47 type_name: &root_node.type_name,
48 value: root_node.to_string(variable_cache),
49 source_location: root_node.source_location.clone(),
50 children: recurse_variables(variable_cache, root_node.variable_key, None),
51 }
52 }
53
54 fn recurse_variables(
56 variable_cache: &VariableCache,
57 parent_variable_key: ObjectRef,
58 max_children: Option<usize>,
59 ) -> Vec<VariableTreeNode<'_>> {
60 let mut children = variable_cache.get_children(parent_variable_key);
61
62 let mut out = Vec::new();
63
64 loop {
65 if let Some(max_count) = max_children
66 && out.len() >= max_count
67 {
68 let remaining = children.clone().count();
70 if remaining > 1 {
71 break;
72 }
73 }
74 let Some(child_variable) = children.next() else {
75 break;
76 };
77
78 out.push(VariableTreeNode {
79 name: &child_variable.name,
80 type_name: &child_variable.type_name,
81 value: child_variable.to_string(variable_cache),
82 children: recurse_variables(
83 variable_cache,
84 child_variable.variable_key,
85 child_variable.type_name.inner().is_array().then_some(50),
87 ),
88 source_location: child_variable.source_location.clone(),
89 });
90 }
91
92 let remaining = children.count();
93 if remaining > 0 {
94 out.push(VariableTreeNode {
95 name: &VariableName::Artifical,
96 type_name: &VariableType::Unknown,
97 value: format!("... and {remaining} more"),
98 children: Vec::new(),
99 source_location: None,
100 });
101 }
102
103 out
104 }
105
106 let mut state = serializer.serialize_struct("Variables", 1)?;
107 state.serialize_field("Child Variables", &recurse_cache(self))?;
108 state.end()
109 }
110}
111
112impl VariableCache {
113 fn new(mut variable: Variable) -> Self {
114 let key = get_object_reference();
115
116 variable.variable_key = key;
117
118 VariableCache {
119 root_variable_key: key,
120 variable_hash_map: BTreeMap::from([(key, variable)]),
121 }
122 }
123
124 pub fn new_dwarf_cache(
132 entries_offset: UnitOffset,
133 name: VariableName,
134 unit_info: &UnitInfo,
135 ) -> Result<Self, DebugError> {
136 let mut static_root_variable = Variable::new(Some(unit_info));
137 static_root_variable.variable_node_type =
138 VariableNodeType::DirectLookup(unit_info.debug_info_offset()?, entries_offset);
139 static_root_variable.name = name;
140
141 Ok(VariableCache::new(static_root_variable))
142 }
143
144 pub fn new_static_cache() -> Self {
148 let mut static_root_variable = Variable::new(None);
149 static_root_variable.variable_node_type = VariableNodeType::UnitsLookup;
150 static_root_variable.name = VariableName::StaticScopeRoot;
151
152 VariableCache::new(static_root_variable)
153 }
154
155 pub fn root_variable(&self) -> &Variable {
157 &self.variable_hash_map[&self.root_variable_key]
158 }
159
160 pub fn len(&self) -> usize {
163 self.variable_hash_map.len()
164 }
165
166 pub fn is_empty(&self) -> bool {
168 self.variable_hash_map.is_empty()
169 }
170
171 pub fn create_variable(
173 &mut self,
174 parent_key: ObjectRef,
175 unit_info: Option<&UnitInfo>,
176 ) -> Result<Variable, DebugError> {
177 if !self.variable_hash_map.contains_key(&parent_key) {
179 return Err(DebugError::Other(format!(
180 "VariableCache: Attempted to add a new variable with non existent `parent_key`: {parent_key:?}. Please report this as a bug"
181 )));
182 }
183
184 let mut variable_to_add = Variable::new(unit_info);
185 variable_to_add.parent_key = parent_key;
186
187 variable_to_add.variable_key = get_object_reference();
189
190 tracing::trace!(
191 "VariableCache: Add Variable: key={:?}, parent={:?}, name={:?}",
192 variable_to_add.variable_key,
193 variable_to_add.parent_key,
194 &variable_to_add.name
195 );
196
197 match self.variable_hash_map.entry(variable_to_add.variable_key) {
198 Entry::Occupied(_) => {
199 return Err(DebugError::Other(format!(
200 "Attempt to insert a new `Variable`:{:?} with a duplicate cache key: {:?}. Please report this as a bug.",
201 variable_to_add.name, variable_to_add.variable_key
202 )));
203 }
204 Entry::Vacant(entry) => {
205 entry.insert(variable_to_add.clone());
206 }
207 }
208
209 Ok(variable_to_add)
210 }
211
212 pub fn add_variable(
217 &mut self,
218 parent_key: ObjectRef,
219 cache_variable: &mut Variable,
220 ) -> Result<(), DebugError> {
221 if !self.variable_hash_map.contains_key(&parent_key) {
223 return Err(DebugError::Other(format!(
224 "VariableCache: Attempted to add a new variable: {} with non existent `parent_key`: {:?}. Please report this as a bug",
225 cache_variable.name, parent_key
226 )));
227 }
228
229 cache_variable.parent_key = parent_key;
230
231 if cache_variable.variable_key != ObjectRef::Invalid {
232 return Err(DebugError::Other(format!(
233 "VariableCache: Attempted to add a new variable: {} with already set key: {:?}. Please report this as a bug",
234 cache_variable.name, cache_variable.variable_key
235 )));
236 }
237
238 cache_variable.variable_key = get_object_reference();
240
241 tracing::trace!(
242 "VariableCache: Add Variable: key={:?}, parent={:?}, name={:?}",
243 cache_variable.variable_key,
244 cache_variable.parent_key,
245 cache_variable.name
246 );
247
248 if let Some(old_variable) = self
249 .variable_hash_map
250 .insert(cache_variable.variable_key, cache_variable.clone())
251 {
252 return Err(DebugError::Other(format!(
253 "Attempt to insert a new `Variable`:{:?} with a duplicate cache key: {:?}. Please report this as a bug.",
254 cache_variable.name, old_variable.variable_key
255 )));
256 }
257
258 Ok(())
259 }
260
261 pub fn update_variable(&mut self, cache_variable: &Variable) -> Result<(), DebugError> {
265 tracing::trace!(
267 "VariableCache: Update Variable, key={:?}, name={:?}",
268 cache_variable.variable_key,
269 &cache_variable.name
270 );
271
272 let Some(prev_entry) = self.variable_hash_map.get_mut(&cache_variable.variable_key) else {
273 return Err(DebugError::Other(format!(
274 "Attempt to update an existing `Variable`:{:?} with a non-existent cache key: {:?}. Please report this as a bug.",
275 cache_variable.name, cache_variable.variable_key
276 )));
277 };
278
279 if cache_variable != prev_entry {
280 tracing::trace!("Updated: {:?}", cache_variable);
281 tracing::trace!("Previous: {:?}", prev_entry);
282 *prev_entry = cache_variable.clone();
283 }
284
285 Ok(())
286 }
287
288 pub fn get_variable_by_key(&self, variable_key: ObjectRef) -> Option<Variable> {
290 self.variable_hash_map.get(&variable_key).cloned()
291 }
292
293 pub fn get_variable_by_name_and_parent(
296 &self,
297 variable_name: &VariableName,
298 parent_key: ObjectRef,
299 ) -> Option<Variable> {
300 let child_variables = self.variable_hash_map.values().filter(|child_variable| {
301 &child_variable.name == variable_name && child_variable.parent_key == parent_key
302 });
303
304 let mut first_iter = child_variables.clone();
306 let first = first_iter.next();
307 let more = first_iter.next().is_some();
308
309 if more {
310 let (last_index, last) = child_variables.enumerate().last().unwrap();
311 tracing::error!(
312 "Found {} variables with parent_key={:?} and name={}. Please report this as a bug.",
313 last_index + 1,
314 parent_key,
315 variable_name
316 );
317 Some(last.clone())
318 } else {
319 first.cloned()
320 }
321 }
322
323 pub fn get_variable_by_name(&self, variable_name: &VariableName) -> Option<Variable> {
327 let mut child_variables = self
328 .variable_hash_map
329 .values()
330 .filter(|child_variable| child_variable.name.eq(variable_name));
331
332 let first = child_variables.next();
333 let more = child_variables.next().is_some();
334
335 if more {
336 tracing::warn!(
337 "Found {} variables with name={}. Please report this as a bug.",
338 self.variable_hash_map.len(),
339 variable_name
340 );
341 }
342
343 first.cloned()
344 }
345
346 pub fn get_children(&self, parent_key: ObjectRef) -> impl Iterator<Item = &Variable> + Clone {
349 self.variable_hash_map
350 .values()
351 .filter(move |child_variable| child_variable.parent_key == parent_key)
352 }
353
354 pub fn has_children(&self, parent_variable: &Variable) -> bool {
356 self.get_children(parent_variable.variable_key)
357 .next()
358 .is_some()
359 }
360
361 pub fn adopt_grand_children(
368 &mut self,
369 parent_variable: &Variable,
370 obsolete_child_variable: &Variable,
371 ) -> Result<(), Error> {
372 if obsolete_child_variable.type_name == VariableType::Unknown
373 || obsolete_child_variable.variable_node_type != VariableNodeType::DoNotRecurse
374 {
375 self.variable_hash_map
377 .values_mut()
378 .filter(|search_variable| {
379 search_variable.parent_key == obsolete_child_variable.variable_key
380 })
381 .for_each(|grand_child| grand_child.parent_key = parent_variable.variable_key);
382 self.remove_cache_entry(obsolete_child_variable.variable_key)?;
384 }
385 Ok(())
386 }
387
388 pub fn remove_cache_entry_children(
390 &mut self,
391 parent_variable_key: ObjectRef,
392 ) -> Result<(), Error> {
393 let children = self
394 .variable_hash_map
395 .values()
396 .filter(|child_variable| child_variable.parent_key == parent_variable_key)
397 .cloned()
398 .collect::<Vec<Variable>>();
399
400 for child in children {
401 self.remove_cache_entry(child.variable_key)?;
402 }
403
404 Ok(())
405 }
406 pub fn remove_cache_entry(&mut self, variable_key: ObjectRef) -> Result<(), Error> {
408 self.remove_cache_entry_children(variable_key)?;
409 if self.variable_hash_map.remove(&variable_key).is_none() {
410 return Err(Error::Other(format!(
411 "Failed to remove a `VariableCache` entry with key: {variable_key:?}. Please report this as a bug."
412 )));
413 };
414 Ok(())
415 }
416 pub fn recurse_deferred_variables(
420 &mut self,
421 debug_info: &DebugInfo,
422 memory: &mut dyn MemoryInterface,
423 max_recursion_depth: usize,
424 frame_info: StackFrameInfo<'_>,
425 ) {
426 let mut parent_variable = self.root_variable().clone();
427
428 self.recurse_deferred_variables_internal(
429 debug_info,
430 memory,
431 &mut parent_variable,
432 max_recursion_depth,
433 0,
434 frame_info,
435 )
436 }
437
438 fn recurse_deferred_variables_internal(
439 &mut self,
440 debug_info: &DebugInfo,
441 memory: &mut dyn MemoryInterface,
442 parent_variable: &mut Variable,
443 max_recursion_depth: usize,
444 current_recursion_depth: usize,
445 frame_info: StackFrameInfo<'_>,
446 ) {
447 if current_recursion_depth >= max_recursion_depth {
448 return;
449 }
450
451 if debug_info
452 .cache_deferred_variables(self, memory, parent_variable, frame_info)
453 .is_err()
454 {
455 return;
456 };
457
458 let children: Vec<_> = self
459 .get_children(parent_variable.variable_key)
460 .cloned()
461 .collect();
462
463 for mut child in children {
464 self.recurse_deferred_variables_internal(
465 debug_info,
466 memory,
467 &mut child,
468 max_recursion_depth,
469 current_recursion_depth + 1,
470 frame_info,
471 );
472 }
473 }
474
475 pub fn get_discrete_memory_ranges(&self) -> Vec<Range<u64>> {
478 let mut memory_ranges: Vec<Range<u64>> = Vec::new();
479 for variable in self.variable_hash_map.values() {
480 if let Some(mut memory_range) = variable.memory_range() {
481 memory_range.align_to_32_bits();
484 if !memory_ranges.contains(&memory_range) {
485 memory_ranges.push(memory_range);
486 }
487 }
488
489 if matches!(variable.type_name, VariableType::Struct(ref name) if name == "&str") {
492 let children: Vec<_> = self.get_children(variable.variable_key).collect();
493 if !children.is_empty() {
494 let string_length = match children.iter().find(|child_variable| {
495 matches!(child_variable.name, VariableName::Named(ref name) if name == "length")
496 }) {
497 Some(string_length) => {
498 if string_length.is_valid() {
499 string_length.to_string(self).parse().unwrap_or(0_usize)
500 } else {
501 0_usize
502 }
503 }
504 None => 0_usize,
505 };
506 let string_location = match children.iter().find(|child_variable| {
507 matches!(child_variable.name, VariableName::Named(ref name ) if name == "data_ptr")
508 }) {
509 Some(location_value) => {
510 let mut child_variables =
511 self.get_children(location_value.variable_key);
512 if let Some(first_child) = child_variables.next() {
513 first_child
514 .memory_location
515 .memory_address()
516 .unwrap_or(0_u64)
517 } else {
518 0_u64
519 }
520 }
521 None => 0_u64,
522 };
523 if string_location == 0 || string_length == 0 {
524 tracing::warn!(
527 "Failed to find string location or length for variable: {:?}",
528 variable
529 );
530 } else {
531 let mut memory_range =
532 string_location..(string_location + string_length as u64);
533 memory_range.align_to_32_bits();
536 if !memory_ranges.contains(&memory_range) {
537 memory_ranges.push(memory_range);
538 }
539 }
540 }
541 }
542 }
543 memory_ranges
544 }
545}
546
547#[cfg(test)]
548mod test {
549 use termtree::Tree;
550
551 use crate::{
552 Variable, VariableCache, VariableLocation, VariableName, VariableNodeType, VariableType,
553 VariantRole,
554 };
555
556 fn show_tree(cache: &VariableCache) {
557 let tree = build_tree(cache, cache.root_variable());
558
559 println!("{tree}");
560 }
561
562 fn build_tree(cache: &VariableCache, variable: &Variable) -> Tree<String> {
563 let mut entry = Tree::new(format!(
564 "{:?}: name={:?}, type={:?}, value={:?}",
565 variable.variable_key,
566 variable.name,
567 variable.type_name,
568 variable.to_string(cache)
569 ));
570
571 let children = cache.get_children(variable.variable_key);
572
573 for child in children {
574 entry.push(build_tree(cache, child));
575 }
576
577 entry
578 }
579
580 #[test]
581 fn static_cache() {
582 let c = VariableCache::new_static_cache();
583
584 let cache_variable = c.root_variable();
585
586 println!("{cache_variable:#?}");
587
588 assert_eq!(cache_variable.name, VariableName::StaticScopeRoot);
590 assert_eq!(cache_variable.type_name, VariableType::Unknown);
591 assert_eq!(
592 cache_variable.variable_node_type,
593 VariableNodeType::UnitsLookup
594 );
595
596 assert_eq!(cache_variable.to_string(&c), "<unknown>");
597
598 assert_eq!(cache_variable.source_location, None);
599 assert_eq!(cache_variable.memory_location, VariableLocation::Unknown);
600 assert_eq!(cache_variable.byte_size, None);
601 assert_eq!(cache_variable.role, VariantRole::NonVariant);
602 }
603
604 #[test]
605 fn find_children() {
606 let mut cache = VariableCache::new_static_cache();
607 let root_key = cache.root_variable().variable_key;
608
609 let var_1 = cache.create_variable(root_key, None).unwrap();
610
611 let var_2 = cache.create_variable(root_key, None).unwrap();
612
613 let children: Vec<_> = cache.get_children(root_key).collect();
614
615 let expected_children = vec![&var_1, &var_2];
616
617 assert_eq!(children, expected_children);
618 }
619
620 #[test]
621 fn find_entry() {
622 let mut cache = VariableCache::new_static_cache();
623 let root_key = cache.root_variable().variable_key;
624
625 let var_1 = cache.create_variable(root_key, None).unwrap();
626
627 let _var_2 = cache.create_variable(root_key, None).unwrap();
628
629 assert_eq!(cache.get_variable_by_key(var_1.variable_key), Some(var_1));
630 }
631
632 fn build_test_tree() -> (VariableCache, Vec<Variable>) {
649 let mut cache = VariableCache::new_static_cache();
650 let root_key = cache.root_variable().variable_key;
651
652 let var_1 = cache.create_variable(root_key, None).unwrap();
653
654 let var_2 = cache.create_variable(root_key, None).unwrap();
655
656 let var_3 = cache.create_variable(var_2.variable_key, None).unwrap();
657
658 let var_4 = cache.create_variable(var_2.variable_key, None).unwrap();
659
660 let var_5 = cache.create_variable(var_3.variable_key, None).unwrap();
661
662 let var_6 = cache.create_variable(root_key, None).unwrap();
663
664 let var_7 = cache.create_variable(var_6.variable_key, None).unwrap();
665
666 assert_eq!(cache.len(), 8);
667
668 let variables = vec![
669 cache.root_variable().clone(),
670 var_1,
671 var_2,
672 var_3,
673 var_4,
674 var_5,
675 var_6,
676 var_7,
677 ];
678
679 (cache, variables)
680 }
681
682 #[test]
683 fn remove_entry() {
684 let (mut cache, vars) = build_test_tree();
685
686 cache.remove_cache_entry(vars[1].variable_key).unwrap();
688 assert!(cache.get_variable_by_key(vars[1].variable_key).is_none());
689 assert_eq!(cache.len(), 7);
690
691 cache.remove_cache_entry(vars[6].variable_key).unwrap();
693 assert!(cache.get_variable_by_key(vars[6].variable_key).is_none());
694 assert!(cache.get_variable_by_key(vars[7].variable_key).is_none());
695 assert_eq!(cache.len(), 5);
696
697 cache.remove_cache_entry(vars[2].variable_key).unwrap();
699 assert!(cache.get_variable_by_key(vars[2].variable_key).is_none());
700 assert!(cache.get_variable_by_key(vars[3].variable_key).is_none());
701 assert!(cache.get_variable_by_key(vars[4].variable_key).is_none());
702 assert!(cache.get_variable_by_key(vars[5].variable_key).is_none());
703 assert_eq!(cache.len(), 1);
704 }
705
706 #[test]
707 fn find_entry_by_name() {
708 let (mut cache, mut vars) = build_test_tree();
709 let non_unique_name = VariableName::Named("non_unique_name".to_string());
710 let unique_name = VariableName::Named("unique_name".to_string());
711
712 show_tree(&cache);
713
714 vars[3].name = non_unique_name.clone();
715 cache.update_variable(&vars[3]).unwrap();
716
717 show_tree(&cache);
718
719 vars[4].name = unique_name.clone();
720 cache.update_variable(&vars[4]).unwrap();
721
722 show_tree(&cache);
723
724 vars[6].name = non_unique_name.clone();
725 cache.update_variable(&vars[6]).unwrap();
726
727 show_tree(&cache);
728
729 assert!(vars[3].variable_key < vars[6].variable_key);
730
731 let var_3 = cache.get_variable_by_name(&non_unique_name).unwrap();
732 assert_eq!(&var_3, &vars[3]);
733
734 let var_4 = cache.get_variable_by_name(&unique_name).unwrap();
735 assert_eq!(&var_4, &vars[4]);
736
737 let var_6 = cache
738 .get_variable_by_name_and_parent(&non_unique_name, vars[6].parent_key)
739 .unwrap();
740 assert_eq!(&var_6, &vars[6]);
741 }
742
743 #[test]
744 fn adopt_grand_children() {
745 let (mut cache, mut vars) = build_test_tree();
746
747 cache.adopt_grand_children(&vars[2], &vars[3]).unwrap();
748
749 assert!(cache.get_variable_by_key(vars[3].variable_key).is_none());
750
751 let new_children: Vec<_> = cache.get_children(vars[2].variable_key).collect();
752
753 vars[5].parent_key = vars[2].variable_key;
754
755 assert_eq!(new_children, vec![&vars[4], &vars[5]]);
756 }
757}