stackdump_trace/variables/
mod.rs

1//! A module containing functions for finding and reading the variables of frames.
2//!
3//! These are (almost) all pure functions that get all of their context through the parameters.
4//! This was decided because the datastructures that are involved are pretty complex and I didn't
5//! want to add complexity.
6//! All functions can be reasoned with on the function level.
7//!
8
9use crate::{
10    error::TraceError,
11    get_entry_type_reference_tree_recursive,
12    gimli_extensions::{AttributeExt, DebuggingInformationEntryExt},
13    type_value_tree::{
14        value::{StringFormat, Value},
15        variable_type::{Archetype, VariableType},
16        TypeValue, TypeValueNode, TypeValueTree, VariableDataError,
17    },
18    DefaultReader, Location, Variable, VariableKind, VariableLocationResult,
19};
20use bitvec::prelude::*;
21use gimli::{
22    Abbreviations, Attribute, AttributeValue, DebugInfoOffset, DebuggingInformationEntry, Dwarf,
23    EntriesTree, Evaluation, EvaluationResult, Piece, Reader, Unit, UnitHeader, UnitOffset,
24};
25use stackdump_core::device_memory::DeviceMemory;
26use std::{collections::HashMap, pin::Pin};
27
28mod type_value_tree_building;
29
30fn div_ceil(lhs: u64, rhs: u64) -> u64 {
31    let d = lhs / rhs;
32    let r = lhs % rhs;
33    if r > 0 && rhs > 0 {
34        d + 1
35    } else {
36        d
37    }
38}
39/// Gets the string value from the `DW_AT_name` attribute of the given entry
40fn get_entry_name(
41    dwarf: &Dwarf<DefaultReader>,
42    unit: &Unit<DefaultReader, usize>,
43    entry: &DebuggingInformationEntry<DefaultReader, usize>,
44) -> Result<String, TraceError> {
45    if entry.tag() == gimli::constants::DW_TAG_volatile_type
46        || entry.tag() == gimli::constants::DW_TAG_const_type
47    {
48        // These tags don't have a name of their own,
49        // so we must follow the the DW_AT_type attribute that points to another entry
50
51        let abbreviations = dwarf.abbreviations(&unit.header)?;
52
53        get_entry_type_reference_tree_recursive!(
54            variable_type_value_tree = (dwarf, unit, &abbreviations, entry)
55        );
56
57        get_entry_name(dwarf, unit, variable_type_value_tree?.root()?.entry())
58    } else {
59        // Find the attribute
60        let name_attr = entry.required_attr(&unit.header, gimli::constants::DW_AT_name);
61
62        match name_attr {
63            Ok(name_attr) => {
64                // Read as a string type
65                let attr_string = dwarf.attr_string(unit, name_attr.value())?;
66                // Convert to String
67                Ok(attr_string.to_string()?.into())
68            }
69            Err(_) if entry.tag() == gimli::constants::DW_TAG_array_type => {
70                // Arrays can be anonymous
71                return Ok("array".into());
72            }
73            Err(_) if entry.tag() == gimli::constants::DW_TAG_subroutine_type => {
74                // Subroutines can be anonymous
75                return Ok("subroutine".into());
76            }
77            Err(e) => Err(e),
78        }
79    }
80}
81
82/// If available, get the EntriesTree of the `DW_AT_abstract_origin` attribute of the given entry
83fn get_entry_abstract_origin_reference_tree<'abbrev, 'unit>(
84    dwarf: &Dwarf<DefaultReader>,
85    unit_header: &'unit UnitHeader<DefaultReader>,
86    abbreviations: &'abbrev Abbreviations,
87    entry: &DebuggingInformationEntry<DefaultReader>,
88) -> Result<EntriesTree<'abbrev, 'unit, DefaultReader>, GetEntryTreeError> {
89    // Find the attribute
90    let abstract_origin_attr = entry
91        .required_attr(unit_header, gimli::constants::DW_AT_abstract_origin)
92        .map_err(GetEntryTreeError::TraceError)?;
93
94    // Check its offset
95    match abstract_origin_attr.value() {
96        AttributeValue::UnitRef(offset) => {
97            // Get the entries for the type
98            Ok(unit_header
99                .entries_tree(abbreviations, Some(offset))
100                .map_err(|e| GetEntryTreeError::TraceError(e.into()))?)
101        }
102        AttributeValue::DebugInfoRef(offset) => {
103            if let Some(offset) = offset.to_unit_offset(unit_header) {
104                return unit_header
105                    .entries_tree(abbreviations, Some(offset))
106                    .map_err(|e| GetEntryTreeError::TraceError(e.into()));
107            }
108
109            // The offset is not in our current compilation unit. Let's see if we can find the correct one
110            let mut units = dwarf.units();
111            while let Ok(Some(unit_header)) = units.next() {
112                if offset.to_unit_offset(&unit_header).is_some() {
113                    // Yes, we've found the unit. We return it so that the caller can recall us with the correct unit.
114                    // We can't use the correct unit ourselves, because the EntriesTree borrows the unit
115                    return Err(GetEntryTreeError::WrongUnit(unit_header));
116                }
117            }
118
119            Err(GetEntryTreeError::TraceError(
120                TraceError::DebugInfoOffsetUnitNotFound {
121                    debug_info_offset: offset.0,
122                },
123            ))
124        }
125        value => Err(GetEntryTreeError::TraceError(
126            TraceError::WrongAttributeValueType {
127                attribute_name: abstract_origin_attr.name().to_string(),
128                expected_type_name: "UnitRef or DebugInfoRef",
129                gotten_value: format!("{:X?}", value),
130            },
131        )),
132    }
133}
134
135/// Get the EntriesTree of the `DW_AT_type` attribute of the given entry
136fn get_entry_type_reference_tree<'abbrev, 'unit>(
137    dwarf: &Dwarf<DefaultReader>,
138    unit_header: &'unit UnitHeader<DefaultReader, usize>,
139    abbreviations: &'abbrev Abbreviations,
140    entry: &DebuggingInformationEntry<DefaultReader, usize>,
141) -> Result<EntriesTree<'abbrev, 'unit, DefaultReader>, GetEntryTreeError> {
142    // Find the attribute
143    let type_attr = entry
144        .required_attr(unit_header, gimli::constants::DW_AT_type)
145        .map_err(GetEntryTreeError::TraceError)?;
146
147    // Check its offset
148    match type_attr.value() {
149        AttributeValue::UnitRef(offset) => {
150            // Get the entries for the type
151            Ok(unit_header
152                .entries_tree(abbreviations, Some(offset))
153                .map_err(|e| GetEntryTreeError::TraceError(e.into()))?)
154        }
155        AttributeValue::DebugInfoRef(offset) => {
156            if let Some(offset) = offset.to_unit_offset(unit_header) {
157                return unit_header
158                    .entries_tree(abbreviations, Some(offset))
159                    .map_err(|e| GetEntryTreeError::TraceError(e.into()));
160            }
161
162            // The offset is not in our current compilation unit. Let's see if we can find the correct one
163            let mut units = dwarf.units();
164            while let Ok(Some(unit_header)) = units.next() {
165                if offset.to_unit_offset(&unit_header).is_some() {
166                    // Yes, we've found the unit. We return it so that the caller can recall us with the correct unit.
167                    // We can't use the correct unit ourselves, because the EntriesTree borrows the unit
168                    return Err(GetEntryTreeError::WrongUnit(unit_header));
169                }
170            }
171
172            Err(GetEntryTreeError::TraceError(
173                TraceError::DebugInfoOffsetUnitNotFound {
174                    debug_info_offset: offset.0,
175                },
176            ))
177        }
178        value => Err(GetEntryTreeError::TraceError(
179            TraceError::WrongAttributeValueType {
180                attribute_name: type_attr.name().to_string(),
181                expected_type_name: "UnitRef or DebugInfoRef",
182                gotten_value: format!("{:X?}", value),
183            },
184        )),
185    }
186}
187
188pub(crate) enum GetEntryTreeError {
189    WrongUnit(UnitHeader<DefaultReader>),
190    TraceError(TraceError),
191}
192
193impl GetEntryTreeError {
194    fn as_trace_error(self) -> TraceError {
195        match self {
196            Self::TraceError(e) => e,
197            Self::WrongUnit(_) => TraceError::UnitNotFoundAgain,
198        }
199    }
200}
201
202#[macro_export]
203macro_rules! get_entry_abstract_origin_reference_tree_recursive {
204    ($tree_name:ident = ($dwarf:expr, $unit:expr, $abbreviations:expr, $entry:expr)) => {
205        let mut __unit_header = $unit.header.clone();
206        #[allow(unused_mut)]
207        let mut $tree_name = match $crate::variables::get_entry_abstract_origin_reference_tree(
208            $dwarf,
209            &__unit_header,
210            $abbreviations,
211            $entry,
212        ) {
213            Err(crate::variables::GetEntryTreeError::WrongUnit(target_unit)) => {
214                __unit_header = target_unit;
215                crate::variables::get_entry_abstract_origin_reference_tree(
216                    $dwarf,
217                    &__unit_header,
218                    $abbreviations,
219                    $entry,
220                )
221            }
222            value => value,
223        }
224        .map_err(|e| e.as_trace_error());
225    };
226}
227
228#[macro_export]
229macro_rules! get_entry_type_reference_tree_recursive {
230    ($tree_name:ident = ($dwarf:expr, $unit:expr, $abbreviations:expr, $entry:expr)) => {
231        let mut __unit_header = $unit.header.clone();
232        #[allow(unused_mut)]
233        let mut $tree_name = match $crate::variables::get_entry_type_reference_tree(
234            $dwarf,
235            &__unit_header,
236            $abbreviations,
237            $entry,
238        ) {
239            Err(crate::variables::GetEntryTreeError::WrongUnit(target_unit)) => {
240                __unit_header = target_unit;
241                crate::variables::get_entry_type_reference_tree(
242                    $dwarf,
243                    &__unit_header,
244                    $abbreviations,
245                    $entry,
246                )
247            }
248            value => value,
249        }
250        .map_err(|e| e.as_trace_error());
251    };
252}
253
254fn try_read_frame_base<W: funty::Integral>(
255    dwarf: &Dwarf<DefaultReader>,
256    unit: &Unit<DefaultReader, usize>,
257    device_memory: &DeviceMemory<W>,
258    entry: &DebuggingInformationEntry<DefaultReader, usize>,
259) -> Result<Option<W>, TraceError>
260where
261    <W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
262{
263    let frame_base_location = evaluate_location(
264        dwarf,
265        unit,
266        device_memory,
267        entry.attr(gimli::constants::DW_AT_frame_base)?,
268        None,
269    )?;
270    let frame_base_data = get_variable_data(
271        device_memory,
272        core::mem::size_of::<W>() as u64 * 8,
273        frame_base_location,
274    );
275
276    Ok(frame_base_data.ok().map(|data| data.load_le()))
277}
278
279/// Finds the [Location] of the given entry.
280///
281/// This is done based on the `DW_AT_decl_file`, `DW_AT_decl_line` and `DW_AT_decl_column` attributes.
282/// These are normally present on variables and functions.
283fn find_entry_location(
284    dwarf: &Dwarf<DefaultReader>,
285    unit: &Unit<DefaultReader, usize>,
286    entry: &DebuggingInformationEntry<DefaultReader, usize>,
287) -> Result<Location, TraceError> {
288    // Get the attributes
289    let variable_decl_file = entry
290        .attr_value(gimli::constants::DW_AT_decl_file)?
291        .and_then(|f| match f {
292            AttributeValue::FileIndex(index) => Some(index),
293            _ => None,
294        });
295    let variable_decl_line = entry
296        .attr_value(gimli::constants::DW_AT_decl_line)?
297        .and_then(|l| l.udata_value());
298    let variable_decl_column = entry
299        .attr_value(gimli::constants::DW_AT_decl_column)?
300        .and_then(|c| c.udata_value());
301
302    fn path_push(path: &mut String, p: &str) {
303        /// Check if the path in the given string has a unix style root
304        fn has_unix_root(p: &str) -> bool {
305            p.starts_with('/')
306        }
307
308        /// Check if the path in the given string has a windows style root
309        fn has_windows_root(p: &str) -> bool {
310            p.starts_with('\\') || p.get(1..3) == Some(":\\")
311        }
312
313        if has_unix_root(p) || has_windows_root(p) {
314            *path = p.to_string();
315        } else {
316            let dir_separator = if has_windows_root(path.as_str()) {
317                '\\'
318            } else {
319                '/'
320            };
321
322            if !path.ends_with(dir_separator) {
323                path.push(dir_separator);
324            }
325            *path += p;
326        }
327    }
328
329    // The file is given as a number, so we need to search for the real file path
330    let variable_file = if let (Some(variable_decl_file), Some(line_program)) =
331        (variable_decl_file, unit.line_program.as_ref())
332    {
333        // The file paths are stored in the line_program
334        if let Some(file_entry) = line_program.header().file(variable_decl_file) {
335            let mut path = if let Some(comp_dir) = &unit.comp_dir {
336                comp_dir.to_string_lossy()?.into_owned()
337            } else {
338                String::new()
339            };
340
341            // The directory index 0 is defined to correspond to the compilation unit directory
342            if variable_decl_file != 0 {
343                if let Some(directory) = file_entry.directory(line_program.header()) {
344                    path_push(
345                        &mut path,
346                        &dwarf.attr_string(unit, directory)?.to_string_lossy()?,
347                    )
348                }
349            }
350
351            path_push(
352                &mut path,
353                &dwarf
354                    .attr_string(unit, file_entry.path_name())?
355                    .to_string()?,
356            );
357
358            Some(path)
359        } else {
360            None
361        }
362    } else {
363        None
364    };
365
366    Ok(Location {
367        file: variable_file,
368        line: variable_decl_line,
369        column: variable_decl_column,
370    })
371}
372
373/// Reads the DW_AT_data_member_location and returns the entry's bit offset
374fn read_data_member_location(
375    unit_header: &UnitHeader<DefaultReader, usize>,
376    entry: &DebuggingInformationEntry<DefaultReader, usize>,
377) -> Result<u64, TraceError> {
378    // TODO: Sometimes this is not a simple number, but a location expression.
379    // As of writing this has not come up, but I can imagine this is the case for C bitfields.
380    // It is the offset in bits from the base.
381    Ok(entry
382        .required_attr(unit_header, gimli::constants::DW_AT_data_member_location)?
383        .required_udata_value()?
384        * 8)
385}
386
387/// Decodes the type of an entry into a type value tree, however, the value is not yet filled in.
388///
389/// The given node should come from the [get_entry_type_reference_tree]
390/// and [get_entry_abstract_origin_reference_tree] functions.
391fn build_type_value_tree<W: funty::Integral>(
392    dwarf: &Dwarf<DefaultReader>,
393    unit: &Unit<DefaultReader, usize>,
394    abbreviations: &Abbreviations,
395    node: gimli::EntriesTreeNode<DefaultReader>,
396    type_cache: &mut HashMap<DebugInfoOffset, Result<TypeValueTree<W>, TraceError>>,
397) -> Result<TypeValueTree<W>, TraceError> {
398    // Get the root entry and its tag
399    let entry = node.entry();
400    let entry_die_offset = entry.offset().to_debug_info_offset(&unit.header).unwrap();
401
402    if let Some(existing_type) = type_cache.get(&entry_die_offset) {
403        log::trace!(
404            "Using cached type value tree for {:?} at {:X} (tag: {})",
405            get_entry_name(dwarf, unit, entry),
406            entry_die_offset.0,
407            entry.tag()
408        );
409
410        return (*existing_type).clone();
411    }
412
413    log::trace!(
414        "Building type value tree for {:?} at {:X} (tag: {})",
415        get_entry_name(dwarf, unit, entry),
416        entry_die_offset.0,
417        entry.tag()
418    );
419
420    // The tag tells us what the base type it
421    let result = match entry.tag() {
422        gimli::constants::DW_TAG_variant_part => type_value_tree_building::build_tagged_union(
423            dwarf,
424            unit,
425            abbreviations,
426            node,
427            type_cache,
428        ),
429        tag @ gimli::constants::DW_TAG_structure_type
430        | tag @ gimli::constants::DW_TAG_union_type
431        | tag @ gimli::constants::DW_TAG_class_type => type_value_tree_building::build_object(
432            dwarf,
433            unit,
434            abbreviations,
435            node,
436            type_cache,
437            tag,
438        ),
439        gimli::constants::DW_TAG_base_type => {
440            type_value_tree_building::build_base_type(dwarf, unit, node)
441        }
442        gimli::constants::DW_TAG_pointer_type => {
443            type_value_tree_building::build_pointer(dwarf, unit, abbreviations, node, type_cache)
444        }
445        gimli::constants::DW_TAG_array_type => {
446            type_value_tree_building::build_array(dwarf, unit, abbreviations, node, type_cache)
447        }
448        gimli::constants::DW_TAG_typedef => {
449            type_value_tree_building::build_typedef(dwarf, unit, abbreviations, node, type_cache)
450        }
451        gimli::constants::DW_TAG_enumeration_type => type_value_tree_building::build_enumeration(
452            dwarf,
453            unit,
454            abbreviations,
455            node,
456            type_cache,
457        ),
458        gimli::constants::DW_TAG_subroutine_type => {
459            let mut type_value_tree = TypeValueTree::new(TypeValue::default());
460            let mut type_value = type_value_tree.root_mut();
461
462            type_value.data_mut().variable_type.archetype = Archetype::Subroutine;
463            Ok(type_value_tree)
464        } // Ignore
465        gimli::constants::DW_TAG_volatile_type => type_value_tree_building::build_volatile_type(
466            dwarf,
467            unit,
468            abbreviations,
469            node,
470            type_cache,
471        ),
472        gimli::constants::DW_TAG_const_type => {
473            type_value_tree_building::build_const_type(dwarf, unit, abbreviations, node, type_cache)
474        }
475        tag => Err(TraceError::TagNotImplemented {
476            tag_name: tag.to_string(),
477            entry_debug_info_offset: entry.offset().to_debug_info_offset(&unit.header).unwrap().0,
478        }),
479    };
480
481    type_cache
482        .entry(entry_die_offset)
483        .or_insert_with(|| result.clone());
484
485    result
486}
487
488/// Runs the location evaluation of gimli.
489///
490/// - `location`: The `DW_AT_location` attribute value of the entry of the variable we want to get the location of.
491/// This may be a None if the variable has no location attribute.
492fn evaluate_location<W: funty::Integral>(
493    dwarf: &Dwarf<DefaultReader>,
494    unit: &Unit<DefaultReader, usize>,
495    device_memory: &DeviceMemory<W>,
496    location: Option<Attribute<DefaultReader>>,
497    frame_base: Option<W>,
498) -> Result<VariableLocationResult, TraceError>
499where
500    <W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
501{
502    // First, we need to have the actual value
503    let location = match location {
504        Some(location) => location.value(),
505        None => return Ok(VariableLocationResult::NoLocationAttribute),
506    };
507
508    // Then we need to get the location expression. This expression can then later be evaluated by gimli.
509    let location_expression = match location {
510        AttributeValue::Block(ref data) => gimli::Expression(data.clone()),
511        AttributeValue::Exprloc(ref data) => data.clone(),
512        AttributeValue::LocationListsRef(l) => {
513            let mut locations = dwarf.locations(unit, l)?;
514            let mut location = None;
515
516            while let Ok(Some(maybe_location)) = locations.next() {
517                let check_pc = device_memory.register(gimli::Arm::PC)?;
518
519                if check_pc.as_u64() >= maybe_location.range.begin
520                    && check_pc.as_u64() < maybe_location.range.end
521                {
522                    location = Some(maybe_location);
523                    break;
524                }
525            }
526
527            if let Some(location) = location {
528                location.data
529            } else {
530                return Ok(VariableLocationResult::LocationListNotFound);
531            }
532        }
533        _ => unreachable!(),
534    };
535
536    // Turn the expression into an evaluation
537    let result = evaluate_expression(
538        unit,
539        device_memory,
540        frame_base,
541        location_expression.evaluation(unit.encoding()),
542    );
543
544    match result {
545        Err(TraceError::LocationEvaluationStepNotImplemented(step)) => {
546            Ok(VariableLocationResult::LocationEvaluationStepNotImplemented(step))
547        }
548        Err(e) => Err(e),
549        Ok(pieces) if pieces.is_empty() => Ok(VariableLocationResult::NoLocationFound),
550        Ok(pieces) => Ok(VariableLocationResult::LocationsFound(pieces)),
551    }
552}
553
554fn evaluate_expression<W: funty::Integral>(
555    unit: &Unit<DefaultReader, usize>,
556    device_memory: &DeviceMemory<W>,
557    frame_base: Option<W>,
558    mut evaluation: Evaluation<DefaultReader>,
559) -> Result<Vec<Piece<DefaultReader, usize>>, TraceError>
560where
561    <W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
562{
563    // Now we need to evaluate everything.
564    // DWARF has a stack based instruction set that needs to be executed.
565    // Luckily, gimli already implements the bulk of it.
566    // The evaluation stops when it requires some memory that we need to provide.
567    let mut result = evaluation.evaluate()?;
568    while result != EvaluationResult::Complete {
569        log::trace!("Location evaluation result: {:?}", result);
570        match result {
571            EvaluationResult::RequiresRegister {
572                register,
573                base_type,
574            } => {
575                let value = device_memory.register(register)?;
576                let value = match base_type.0 {
577                    0 => gimli::Value::Generic(value.as_u64()),
578                    val => return Err(TraceError::OperationNotImplemented { operation: format!("Other types than generic haven't been implemented yet. base_type value: {val}"), file: file!(), line: line!() } ),
579                };
580                result = evaluation.resume_with_register(value)?;
581            }
582            EvaluationResult::RequiresFrameBase if frame_base.is_some() => {
583                result = evaluation.resume_with_frame_base(
584                    frame_base.ok_or(TraceError::UnknownFrameBase)?.as_u64(),
585                )?;
586            }
587            EvaluationResult::RequiresRelocatedAddress(address) => {
588                // We have no relocations of code
589                result = evaluation.resume_with_relocated_address(address)?;
590            }
591            EvaluationResult::RequiresEntryValue(ex) => {
592                let entry_pieces = evaluate_expression(
593                    unit,
594                    device_memory,
595                    frame_base,
596                    ex.evaluation(unit.encoding()),
597                )?;
598
599                let entry_data = get_variable_data(
600                    device_memory,
601                    W::BITS as u64,
602                    VariableLocationResult::LocationsFound(entry_pieces),
603                )?;
604
605                result = evaluation.resume_with_entry_value(gimli::Value::Generic(
606                    entry_data.load_le::<W>().as_u64(), // TODO: What should be the endianness of this? Our device or the target device?
607                ))?;
608            }
609            EvaluationResult::RequiresMemory {
610                address,
611                size,
612                space: None,
613                base_type: UnitOffset(0),
614            } => {
615                // This arm only accepts the generic base_type, so size should always be equal to the size of W
616                // assert_eq!(size as u32 * 8, W::BITS);
617
618                let mut data = device_memory
619                    .read_slice(address..address + size as u64)?
620                    .ok_or(TraceError::MissingMemory(address))?;
621
622                data.extend(
623                    std::iter::once(0)
624                        .cycle()
625                        .take((W::BITS / 8) as usize - size as usize),
626                );
627
628                let value = gimli::Value::Generic(data.as_bits::<Lsb0>().load_le::<W>().as_u64());
629                result = evaluation.resume_with_memory(value)?;
630            }
631            r => {
632                return Err(TraceError::LocationEvaluationStepNotImplemented(
633                    std::rc::Rc::new(r),
634                ))
635            }
636        }
637    }
638
639    Ok(evaluation.result())
640}
641
642/// Reads the data of a piece of memory
643///
644/// The [Piece] is an indirect result of the [evaluate_location] function.
645///
646/// - `device_memory`: The captured memory of the device
647/// - `piece`: The piece of memory location that tells us which data needs to be read
648/// - `variable_size`: The size of the variable in bytes
649fn get_piece_data<W: funty::Integral>(
650    device_memory: &DeviceMemory<W>,
651    piece: &Piece<DefaultReader, usize>,
652    variable_size: u64,
653) -> Result<Option<bitvec::vec::BitVec<u8, Lsb0>>, VariableDataError>
654where
655    <W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
656{
657    let mut data = match piece.location.clone() {
658        gimli::Location::Empty => return Err(VariableDataError::OptimizedAway),
659        gimli::Location::Register { register } => Some(
660            device_memory
661                .register(register)
662                .map(|r| r.to_ne_bytes().view_bits().to_bitvec()) // TODO: Is this correct? Shouldn't this be the endianness of the target device?
663                .map_err(|e| VariableDataError::NoDataAvailableAt(e.to_string()))?,
664        ),
665        gimli::Location::Address { address } => device_memory
666            .read_slice(address..(address + variable_size))?
667            .map(|b| b.view_bits().to_bitvec()),
668        gimli::Location::Value { value } => {
669            let mut data = BitVec::new();
670
671            match value {
672                gimli::Value::Generic(v) => data.extend(v.view_bits::<Lsb0>()),
673                gimli::Value::I8(v) => data.extend((v as u8).view_bits::<Lsb0>()),
674                gimli::Value::U8(v) => data.extend(v.view_bits::<Lsb0>()),
675                gimli::Value::I16(v) => data.extend((v as u16).view_bits::<Lsb0>()),
676                gimli::Value::U16(v) => data.extend(v.view_bits::<Lsb0>()),
677                gimli::Value::I32(v) => data.extend((v as u32).view_bits::<Lsb0>()),
678                gimli::Value::U32(v) => data.extend(v.view_bits::<Lsb0>()),
679                gimli::Value::I64(v) => data.extend((v as u64).view_bits::<Lsb0>()),
680                gimli::Value::U64(v) => data.extend(v.view_bits::<Lsb0>()),
681                gimli::Value::F32(v) => data.extend(v.to_bits().view_bits::<Lsb0>()),
682                gimli::Value::F64(v) => data.extend(v.to_bits().view_bits::<Lsb0>()),
683            }
684
685            Some(data)
686        }
687        gimli::Location::Bytes { value } => value
688            .get(0..variable_size as usize)
689            .map(|b| b.view_bits().to_bitvec()),
690        gimli::Location::ImplicitPointer {
691            value: _,
692            byte_offset: _,
693        } => {
694            return Err(VariableDataError::OperationNotImplemented {
695                operation: "`ImplicitPointer` location not yet supported".into(),
696                file: file!(),
697                line: line!(),
698            })
699        }
700    };
701
702    // The piece can also specify offsets and a size, so adapt what we've just read to that
703    if let Some(data) = data.as_mut() {
704        if let Some(offset) = piece.bit_offset {
705            data.drain(0..offset as usize);
706        }
707        if let Some(length) = piece.size_in_bits {
708            data.truncate(length as usize);
709        }
710    }
711
712    Ok(data)
713}
714
715/// Get all of the available variable data based on the [VariableLocationResult] of the [evaluate_location] function.
716///
717/// - `device_memory`: All the captured memory of the device
718/// - `variable_size`: The size of the variable in bits
719/// - `variable_location`: The location of the variable
720fn get_variable_data<W: funty::Integral>(
721    device_memory: &DeviceMemory<W>,
722    variable_size: u64,
723    variable_location: VariableLocationResult,
724) -> Result<BitVec<u8, Lsb0>, VariableDataError>
725where
726    <W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
727{
728    match variable_location {
729        VariableLocationResult::NoLocationAttribute => Err(VariableDataError::OptimizedAway),
730        VariableLocationResult::LocationListNotFound => Err(VariableDataError::OptimizedAway),
731        VariableLocationResult::NoLocationFound => Err(VariableDataError::OptimizedAway),
732        VariableLocationResult::LocationsFound(pieces) => {
733            let mut data = BitVec::new();
734
735            // Ceil-div with 8 to get the bytes we need to read
736            let variable_size_bytes = div_ceil(variable_size, 8);
737
738            // Get all the data of the pieces
739            for piece in pieces {
740                let piece_data = get_piece_data(device_memory, &piece, variable_size_bytes)?;
741
742                if let Some(mut piece_data) = piece_data {
743                    // TODO: Is this always in sequential order? We now assume that it is
744                    data.append(&mut piece_data);
745                } else {
746                    // Data is not on the stack
747                    return Err(VariableDataError::NoDataAvailableAt(format!(
748                        "{:X?}",
749                        piece.location
750                    )));
751                };
752            }
753
754            Ok(data)
755        }
756        VariableLocationResult::LocationEvaluationStepNotImplemented(step) => Err(
757            VariableDataError::UnimplementedLocationEvaluationStep(format!("{:?}", step)),
758        ),
759    }
760}
761
762fn read_base_type<W: funty::Integral>(
763    encoding: gimli::DwAte,
764    data: &BitSlice<u8, Lsb0>,
765) -> Result<Value<W>, VariableDataError> {
766    match encoding {
767        gimli::constants::DW_ATE_unsigned | gimli::constants::DW_ATE_unsigned_char => {
768            match data.len() {
769                8 => Ok(Value::Uint(data.load_le::<u8>() as _)),
770                16 => Ok(Value::Uint(data.load_le::<u16>() as _)),
771                32 => Ok(Value::Uint(data.load_le::<u32>() as _)),
772                64 => Ok(Value::Uint(data.load_le::<u64>() as _)),
773                128 => Ok(Value::Uint(data.load_le::<u128>() as _)),
774                _ => Err(VariableDataError::InvalidSize { bits: data.len() }),
775            }
776        }
777        gimli::constants::DW_ATE_signed | gimli::constants::DW_ATE_signed_char => {
778            match data.len() {
779                8 => Ok(Value::Int(data.load_le::<u8>() as _)),
780                16 => Ok(Value::Int(data.load_le::<u16>() as _)),
781                32 => Ok(Value::Int(data.load_le::<u32>() as _)),
782                64 => Ok(Value::Int(data.load_le::<u64>() as _)),
783                128 => Ok(Value::Int(data.load_le::<u128>() as _)),
784                _ => Err(VariableDataError::InvalidSize { bits: data.len() }),
785            }
786        }
787        gimli::constants::DW_ATE_float => match data.len() {
788            32 => Ok(Value::Float(f32::from_bits(data.load_le::<u32>()) as _)),
789            64 => Ok(Value::Float(f64::from_bits(data.load_le::<u64>()) as _)),
790            _ => Err(VariableDataError::InvalidSize { bits: data.len() }),
791        },
792        gimli::constants::DW_ATE_boolean => Ok(Value::Bool(data.iter().any(|v| *v))),
793        gimli::constants::DW_ATE_address => match data.len() {
794            8 => Ok(Value::Address(
795                data.load_le::<u8>().try_into().ok().unwrap(),
796            )),
797            16 => Ok(Value::Address(
798                data.load_le::<u16>().try_into().ok().unwrap(),
799            )),
800            32 => Ok(Value::Address(
801                data.load_le::<u32>().try_into().ok().unwrap(),
802            )),
803            64 => Ok(Value::Address(
804                data.load_le::<u64>().try_into().ok().unwrap(),
805            )),
806            _ => Err(VariableDataError::InvalidSize { bits: data.len() }),
807        },
808        t => Err(VariableDataError::UnsupportedBaseType {
809            base_type: t,
810            data: data.to_bitvec(),
811        }),
812    }
813}
814
815/// Read some bit data into the value of the give variable. If there is an error, that error will be placed in the value field as well
816fn read_variable_data<W: funty::Integral>(
817    mut variable: Pin<&mut TypeValueNode<W>>,
818    data: &BitSlice<u8, Lsb0>,
819    device_memory: &DeviceMemory<W>,
820    type_cache: &mut HashMap<DebugInfoOffset, Result<TypeValueTree<W>, TraceError>>,
821) {
822    // We may not have enough data in some cases
823    // I don't know why that is, so let's just print a warning
824    if variable.data().bit_length() > data.len() as u64 {
825        log::warn!(
826            "Variable of type {} claims to take up {} bits, but only {} bits are available",
827            variable.data().variable_type.name,
828            variable.data().bit_range.end,
829            data.len()
830        );
831    }
832
833    match variable.data().variable_type.archetype {
834        Archetype::TaggedUnion => {
835            // The first child must be the descriminator and not one of the variants
836            assert!(variable.front_mut().unwrap().data().name == "discriminant");
837
838            // We have to read the discriminator, then select the active variant and then read that
839            read_variable_data(
840                variable.front_mut().unwrap(),
841                data,
842                device_memory,
843                type_cache,
844            );
845
846            let discriminator_value = match &variable.front().unwrap().data().variable_value {
847                Ok(value) => value.clone(),
848                _ => {
849                    return;
850                }
851            };
852
853            // We know the discriminator value, so now we need to hunt for the active variant.
854            // There may not be one though
855            let active_variant = variable
856                .iter_mut()
857                .skip(1)
858                .find(|variant| variant.data().variable_value.as_ref() == Ok(&discriminator_value));
859
860            if let Some(active_variant) = active_variant {
861                read_variable_data(active_variant, data, device_memory, type_cache);
862            } else if let Some(default_variant) = variable
863                .iter_mut()
864                .skip(1)
865                .find(|variant| variant.data().variable_value.is_err())
866            {
867                // There is no active variant, so we need to go for the default
868                read_variable_data(default_variant, data, device_memory, type_cache);
869            }
870        }
871        Archetype::TaggedUnionVariant => {
872            read_variable_data(
873                variable.front_mut().unwrap(),
874                data,
875                device_memory,
876                type_cache,
877            );
878        }
879        Archetype::Structure
880        | Archetype::Union
881        | Archetype::Class
882        | Archetype::ObjectMemberPointer => {
883            // Every member of this object is a child in the tree.
884            // We simply need to read every child.
885
886            for child in variable.iter_mut() {
887                read_variable_data(child, data, device_memory, type_cache);
888            }
889
890            if &variable.data().variable_type.name == "&str" {
891                // This is a string
892                let pointer = &variable
893                    .iter()
894                    .find(|field| field.data().name == "data_ptr")
895                    .ok_or(())
896                    .map(|node| &node.data().variable_value);
897                let length = &variable
898                    .iter()
899                    .find(|field| field.data().name == "length")
900                    .ok_or(())
901                    .map(|node| &node.data().variable_value);
902
903                match (pointer, length) {
904                    (Ok(Ok(Value::Address(pointer))), Ok(Ok(Value::Uint(length))))
905                        if *length < 64 * 1024 =>
906                    {
907                        // We can read the data. This works because the length field denotes the byte size, not the char size
908                        let data = device_memory
909                            .read_slice(pointer.as_u64()..pointer.as_u64() + *length as u64);
910                        if let Ok(Some(data)) = data {
911                            variable.data_mut().variable_value =
912                                Ok(Value::String(data, StringFormat::Utf8));
913                        } else {
914                            // There's something wrong. Fall back to treating the string as an object
915                            variable.data_mut().variable_value = Ok(Value::Object);
916                        }
917                    }
918                    (Ok(Ok(Value::Address(_))), Ok(Ok(Value::Uint(length))))
919                        if *length >= 64 * 1024 =>
920                    {
921                        log::warn!(
922                            "We started decoding the string {}, but it is {length} bytes long",
923                            variable.data().name
924                        );
925                        // There's something wrong. Fall back to treating the string as an object
926                        variable.data_mut().variable_value = Ok(Value::Object);
927                    }
928                    _ => {
929                        log::error!(
930                            "We started decoding the string {}, but found an error",
931                            variable.data().name
932                        );
933                        // There's something wrong. Fall back to treating the string as an object
934                        variable.data_mut().variable_value = Ok(Value::Object);
935                    }
936                }
937            } else {
938                // This is a normal object
939                variable.data_mut().variable_value = Ok(Value::Object);
940            }
941        }
942        Archetype::BaseType(encoding) => {
943            if variable.data().bit_length() == 0 && variable.data().variable_type.name == "()" {
944                variable.data_mut().variable_value = Ok(Value::Unit);
945            } else {
946                variable.data_mut().variable_value =
947                    match data.get(variable.data().bit_range_usize()) {
948                        Some(data) => read_base_type(encoding, data),
949                        None => Err(VariableDataError::NoDataAvailable),
950                    };
951            }
952        }
953        Archetype::Pointer(die_offset) => {
954            // The variable is a number that is the address of the pointee.
955            // The pointee is not part of this tree yet and has to be looked up through the type_cache.
956            // This is done so that we cannot get an infinite recursive type due to e.g. linked lists.
957
958            variable.data_mut().variable_value = match data.get(variable.data().bit_range_usize()) {
959                Some(data) => read_base_type(gimli::constants::DW_ATE_address, data),
960                None => Err(VariableDataError::NoDataAvailable),
961            };
962
963            let address = match variable.data().variable_value {
964                Ok(Value::Address(addr)) => Ok(addr),
965                _ => Err(VariableDataError::InvalidPointerData),
966            };
967
968            let pointee_tree_clone = match type_cache
969                .get(&die_offset)
970                .expect("Pointers must have their pointee type cached")
971                .clone()
972            {
973                Ok(pointee_tree_clone) => pointee_tree_clone,
974                Err(_) => TypeValueTree::new(TypeValue {
975                    name: "Pointee".into(),
976                    variable_type: VariableType {
977                        archetype: Archetype::Unknown,
978                        ..Default::default()
979                    },
980                    bit_range: 0..0,
981                    variable_value: Err(VariableDataError::Unknown),
982                }),
983            };
984            variable.push_back(pointee_tree_clone);
985            let mut pointee = variable.back_mut().unwrap();
986
987            match address {
988                Ok(address) if address == W::ZERO => {
989                    pointee.data_mut().variable_value = Err(VariableDataError::NullPointer)
990                }
991                Ok(address) => {
992                    let pointee_data = device_memory.read_slice(
993                        address.as_u64()
994                            ..address.as_u64() + div_ceil(pointee.data().bit_range.end, 8),
995                    );
996
997                    match pointee_data {
998                        Ok(Some(pointee_data)) => {
999                            read_variable_data(
1000                                pointee,
1001                                pointee_data.view_bits(),
1002                                device_memory,
1003                                type_cache,
1004                            );
1005                        }
1006                        Ok(None) => {
1007                            pointee.data_mut().variable_value =
1008                                Err(VariableDataError::NoDataAvailable);
1009                        }
1010                        Err(e) => {
1011                            pointee.data_mut().variable_value = Err(e.into());
1012                        }
1013                    }
1014                }
1015                Err(e) => pointee.data_mut().variable_value = Err(e),
1016            }
1017        }
1018        Archetype::Array => {
1019            variable.data_mut().variable_value = Ok(Value::Array);
1020            // The tree has all children that we have to read. These are the elements of the array
1021            for mut element in variable.iter_mut() {
1022                match data.get(element.data().bit_range_usize()) {
1023                    Some(_) => read_variable_data(element, data, device_memory, type_cache),
1024                    None => {
1025                        element.data_mut().variable_value = Err(VariableDataError::NoDataAvailable)
1026                    }
1027                }
1028            }
1029        }
1030        Archetype::Enumeration => {
1031            variable.data_mut().variable_value = Ok(Value::Enumeration);
1032
1033            // The first child of the enumeration is the base integer. We only have to read that one.
1034            read_variable_data(
1035                variable.front_mut().expect("Enumerations have a child"),
1036                data,
1037                device_memory,
1038                type_cache,
1039            );
1040        }
1041        Archetype::Typedef => {
1042            variable.data_mut().variable_value = Ok(Value::Typedef);
1043
1044            // The first child of the enumeration is the base integer. We only have to read that one.
1045            read_variable_data(
1046                variable.front_mut().expect("Typedefs have a child"),
1047                data,
1048                device_memory,
1049                type_cache,
1050            );
1051        }
1052        Archetype::Enumerator => {
1053            // Ignore, we don't have to do anything
1054        }
1055        Archetype::Subroutine => {
1056            variable.data_mut().variable_value = Ok(Value::Object);
1057            // Ignore, there's nothing to do
1058        }
1059        Archetype::Unknown => {
1060            // Ignore, we don't know what to do
1061        }
1062    }
1063}
1064
1065fn read_variable_entry<W: funty::Integral>(
1066    dwarf: &Dwarf<DefaultReader>,
1067    unit: &Unit<DefaultReader, usize>,
1068    abbreviations: &Abbreviations,
1069    device_memory: &DeviceMemory<W>,
1070    frame_base: Option<W>,
1071    entry: &DebuggingInformationEntry<DefaultReader, usize>,
1072    type_cache: &mut HashMap<DebugInfoOffset, Result<TypeValueTree<W>, TraceError>>,
1073) -> Result<Option<Variable<W>>, TraceError>
1074where
1075    <W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
1076{
1077    get_entry_abstract_origin_reference_tree_recursive!(
1078        abstract_origin_tree = (dwarf, unit, abbreviations, entry)
1079    );
1080    let mut abstract_origin_tree = abstract_origin_tree.ok();
1081
1082    let abstract_origin_node = abstract_origin_tree
1083        .as_mut()
1084        .and_then(|tree| tree.root().ok());
1085    let abstract_origin_entry = abstract_origin_node.as_ref().map(|node| node.entry());
1086
1087    // Get the name of the variable
1088    let variable_name = get_entry_name(dwarf, unit, entry);
1089
1090    // Alternatively, get the name from the abstract origin
1091    let mut variable_name = match (variable_name, abstract_origin_entry) {
1092        (Err(_), Some(entry)) => get_entry_name(dwarf, unit, entry),
1093        (variable_name, _) => variable_name,
1094    };
1095
1096    if entry.tag() == gimli::constants::DW_TAG_formal_parameter && variable_name.is_err() {
1097        log::trace!("Formal parameter does not have a name, renaming it to 'param'");
1098        variable_name = Ok("param".into());
1099    }
1100
1101    // Get the type of the variable or its abstract origin
1102    get_entry_type_reference_tree_recursive!(
1103        variable_type_tree = (dwarf, unit, abbreviations, entry)
1104    );
1105
1106    get_entry_abstract_origin_reference_tree_recursive!(
1107        abstract_origin_tree = (dwarf, unit, abbreviations, entry)
1108    );
1109
1110    let variable_type_value_tree = (|| match (variable_type_tree, abstract_origin_tree) {
1111        (Ok(mut variable_type_tree), _) => {
1112            let type_root = variable_type_tree.root()?;
1113            build_type_value_tree(dwarf, unit, abbreviations, type_root, type_cache)
1114        }
1115        (_, Ok(mut abstract_origin_tree)) => {
1116            let abstract_entry = abstract_origin_tree.root()?.entry().clone();
1117            get_entry_type_reference_tree_recursive!(
1118                abstract_variable_type_tree = (dwarf, unit, abbreviations, &abstract_entry)
1119            );
1120
1121            match abstract_variable_type_tree {
1122                Ok(mut abstract_variable_type_tree) => {
1123                    let type_root = abstract_variable_type_tree.root()?;
1124                    build_type_value_tree(dwarf, unit, abbreviations, type_root, type_cache)
1125                }
1126                Err(e) => Err(e),
1127            }
1128        }
1129        (Err(e), _) => Err(e),
1130    })();
1131
1132    let variable_kind = VariableKind {
1133        zero_sized: variable_type_value_tree
1134            .as_ref()
1135            .map(|vt| vt.data().bit_length() == 0)
1136            .unwrap_or_default(),
1137        inlined: abstract_origin_entry.is_some(),
1138        parameter: entry.tag() == gimli::constants::DW_TAG_formal_parameter,
1139    };
1140
1141    // Get the location of the variable
1142    let mut variable_file_location = find_entry_location(dwarf, unit, entry)?;
1143    if let (None, Some(abstract_origin_entry)) =
1144        (&variable_file_location.file, abstract_origin_entry)
1145    {
1146        variable_file_location = find_entry_location(dwarf, unit, abstract_origin_entry)?;
1147    }
1148
1149    match (variable_name, variable_type_value_tree) {
1150        (Ok(variable_name), Ok(variable_type_value_tree)) if variable_kind.zero_sized => {
1151            Ok(Some(Variable {
1152                name: variable_name,
1153                kind: variable_kind,
1154                type_value: variable_type_value_tree,
1155                location: variable_file_location,
1156            }))
1157        }
1158        (Ok(variable_name), Ok(mut variable_type_value_tree)) => {
1159            let location_attr = entry.attr(gimli::constants::DW_AT_location)?;
1160
1161            let location_attr = match (location_attr, abstract_origin_entry) {
1162                (None, Some(entry)) => entry.attr(gimli::constants::DW_AT_location)?,
1163                (location_attr, _) => location_attr,
1164            };
1165
1166            // Get the location of the variable
1167            let variable_location =
1168                evaluate_location(dwarf, unit, device_memory, location_attr, frame_base)?;
1169
1170            log::debug!(
1171                "Reading variable data for `{variable_name}` at {variable_location:X?} of {} bits",
1172                variable_type_value_tree.data().bit_length()
1173            );
1174            let variable_data = get_variable_data(
1175                device_memory,
1176                variable_type_value_tree.data().bit_length(),
1177                variable_location,
1178            );
1179
1180            match variable_data {
1181                // We have the data so read the variable using it
1182                Ok(variable_data) => read_variable_data(
1183                    variable_type_value_tree.root_mut(),
1184                    &variable_data,
1185                    device_memory,
1186                    type_cache,
1187                ),
1188                // We couldn't get the data, so set the value to the error we got
1189                Err(e) => {
1190                    variable_type_value_tree
1191                        .root_mut()
1192                        .data_mut()
1193                        .variable_value = Err(e)
1194                }
1195            }
1196
1197            Ok(Some(Variable {
1198                name: variable_name,
1199                kind: variable_kind,
1200                type_value: variable_type_value_tree,
1201                location: variable_file_location,
1202            }))
1203        }
1204        (Ok(variable_name), Err(type_error)) => {
1205            log::info!(
1206                "Could not read the type of variable `{}` of entry {:X?}: {}",
1207                variable_name,
1208                entry.offset().to_debug_info_offset(&unit.header),
1209                type_error
1210            );
1211            Ok(None)
1212        }
1213        (Err(name_error), _) => {
1214            log::debug!(
1215                "Could not get the name of a variable of entry {:X?}: {}",
1216                entry.offset().to_debug_info_offset(&unit.header),
1217                name_error
1218            );
1219            Ok(None)
1220        }
1221    }
1222}
1223
1224pub fn find_variables_in_function<W: funty::Integral>(
1225    dwarf: &Dwarf<DefaultReader>,
1226    unit: &Unit<DefaultReader, usize>,
1227    abbreviations: &Abbreviations,
1228    device_memory: &DeviceMemory<W>,
1229    node: gimli::EntriesTreeNode<DefaultReader>,
1230    type_cache: &mut HashMap<DebugInfoOffset, Result<TypeValueTree<W>, TraceError>>,
1231) -> Result<Vec<Variable<W>>, TraceError>
1232where
1233    <W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
1234{
1235    #[allow(clippy::too_many_arguments)]
1236    fn recursor<W: funty::Integral>(
1237        dwarf: &Dwarf<DefaultReader>,
1238        unit: &Unit<DefaultReader, usize>,
1239        abbreviations: &Abbreviations,
1240        device_memory: &DeviceMemory<W>,
1241        node: gimli::EntriesTreeNode<DefaultReader>,
1242        variables: &mut Vec<Variable<W>>,
1243        mut frame_base: Option<W>,
1244        type_cache: &mut HashMap<DebugInfoOffset, Result<TypeValueTree<W>, TraceError>>,
1245    ) -> Result<(), TraceError>
1246    where
1247        <W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
1248    {
1249        let entry = node.entry();
1250
1251        log::trace!(
1252            "Checking out the entry @ .debug_info: {:X}",
1253            unit.header.offset().as_debug_info_offset().unwrap().0 + entry.offset().0
1254        );
1255
1256        if let Some(new_frame_base) = try_read_frame_base(dwarf, unit, device_memory, entry)? {
1257            frame_base = Some(new_frame_base);
1258        }
1259
1260        if entry.tag() == gimli::constants::DW_TAG_variable
1261            || entry.tag() == gimli::constants::DW_TAG_formal_parameter
1262        {
1263            if let Some(variable) = read_variable_entry(
1264                dwarf,
1265                unit,
1266                abbreviations,
1267                device_memory,
1268                frame_base,
1269                entry,
1270                type_cache,
1271            )? {
1272                variables.push(variable);
1273            }
1274        }
1275
1276        let mut children = node.children();
1277        while let Some(child) = children.next()? {
1278            recursor(
1279                dwarf,
1280                unit,
1281                abbreviations,
1282                device_memory,
1283                child,
1284                variables,
1285                frame_base,
1286                type_cache,
1287            )?;
1288        }
1289
1290        Ok(())
1291    }
1292
1293    let mut variables = Vec::new();
1294    recursor(
1295        dwarf,
1296        unit,
1297        abbreviations,
1298        device_memory,
1299        node,
1300        &mut variables,
1301        None,
1302        type_cache,
1303    )?;
1304    Ok(variables)
1305}
1306
1307pub fn find_static_variables<W: funty::Integral>(
1308    dwarf: &Dwarf<DefaultReader>,
1309    device_memory: &DeviceMemory<W>,
1310    type_cache: &mut HashMap<DebugInfoOffset, Result<TypeValueTree<W>, TraceError>>,
1311) -> Result<Vec<Variable<W>>, TraceError>
1312where
1313    <W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
1314{
1315    fn recursor<W: funty::Integral>(
1316        dwarf: &Dwarf<DefaultReader>,
1317        unit: &Unit<DefaultReader, usize>,
1318        abbreviations: &Abbreviations,
1319        device_memory: &DeviceMemory<W>,
1320        node: gimli::EntriesTreeNode<DefaultReader>,
1321        variables: &mut Vec<Variable<W>>,
1322        type_cache: &mut HashMap<DebugInfoOffset, Result<TypeValueTree<W>, TraceError>>,
1323    ) -> Result<(), TraceError>
1324    where
1325        <W as funty::Numeric>::Bytes: bitvec::view::BitView<Store = u8>,
1326    {
1327        let entry = node.entry();
1328
1329        match entry.tag() {
1330            gimli::constants::DW_TAG_compile_unit => {}
1331            gimli::constants::DW_TAG_namespace => {}
1332            gimli::constants::DW_TAG_structure_type
1333            | gimli::constants::DW_TAG_subprogram
1334            | gimli::constants::DW_TAG_enumeration_type
1335            | gimli::constants::DW_TAG_base_type
1336            | gimli::constants::DW_TAG_array_type
1337            | gimli::constants::DW_TAG_pointer_type
1338            | gimli::constants::DW_TAG_subroutine_type
1339            | gimli::constants::DW_TAG_typedef
1340            | gimli::constants::DW_TAG_restrict_type
1341            | gimli::constants::DW_TAG_const_type
1342            | gimli::constants::DW_TAG_union_type
1343            | gimli::constants::DW_TAG_volatile_type => return Ok(()),
1344            gimli::constants::DW_TAG_variable => {
1345                if let Some(variable) = read_variable_entry(
1346                    dwarf,
1347                    unit,
1348                    abbreviations,
1349                    device_memory,
1350                    None,
1351                    entry,
1352                    type_cache,
1353                )? {
1354                    variables.push(variable);
1355                }
1356            }
1357            tag => {
1358                log::error!(
1359                    "Unexpected tag in the search of static variables: {} at {:X?}",
1360                    tag,
1361                    entry.offset().to_debug_info_offset(&unit.header)
1362                );
1363                return Ok(());
1364            }
1365        }
1366
1367        let mut children = node.children();
1368        while let Some(child) = children.next()? {
1369            recursor(
1370                dwarf,
1371                unit,
1372                abbreviations,
1373                device_memory,
1374                child,
1375                variables,
1376                type_cache,
1377            )?;
1378        }
1379
1380        Ok(())
1381    }
1382
1383    let mut variables = Vec::new();
1384    let mut units = dwarf.units();
1385    while let Some(unit_header) = units.next()? {
1386        let abbreviations = dwarf.abbreviations(&unit_header)?;
1387        recursor(
1388            dwarf,
1389            &dwarf.unit(unit_header.clone())?,
1390            &abbreviations,
1391            device_memory,
1392            unit_header.entries_tree(&abbreviations, None)?.root()?,
1393            &mut variables,
1394            type_cache,
1395        )?;
1396    }
1397
1398    Ok(variables)
1399}