1use 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}
39fn 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 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 let name_attr = entry.required_attr(&unit.header, gimli::constants::DW_AT_name);
61
62 match name_attr {
63 Ok(name_attr) => {
64 let attr_string = dwarf.attr_string(unit, name_attr.value())?;
66 Ok(attr_string.to_string()?.into())
68 }
69 Err(_) if entry.tag() == gimli::constants::DW_TAG_array_type => {
70 return Ok("array".into());
72 }
73 Err(_) if entry.tag() == gimli::constants::DW_TAG_subroutine_type => {
74 return Ok("subroutine".into());
76 }
77 Err(e) => Err(e),
78 }
79 }
80}
81
82fn 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 let abstract_origin_attr = entry
91 .required_attr(unit_header, gimli::constants::DW_AT_abstract_origin)
92 .map_err(GetEntryTreeError::TraceError)?;
93
94 match abstract_origin_attr.value() {
96 AttributeValue::UnitRef(offset) => {
97 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 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 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
135fn 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 let type_attr = entry
144 .required_attr(unit_header, gimli::constants::DW_AT_type)
145 .map_err(GetEntryTreeError::TraceError)?;
146
147 match type_attr.value() {
149 AttributeValue::UnitRef(offset) => {
150 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 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 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
279fn find_entry_location(
284 dwarf: &Dwarf<DefaultReader>,
285 unit: &Unit<DefaultReader, usize>,
286 entry: &DebuggingInformationEntry<DefaultReader, usize>,
287) -> Result<Location, TraceError> {
288 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 fn has_unix_root(p: &str) -> bool {
305 p.starts_with('/')
306 }
307
308 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 let variable_file = if let (Some(variable_decl_file), Some(line_program)) =
331 (variable_decl_file, unit.line_program.as_ref())
332 {
333 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 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
373fn read_data_member_location(
375 unit_header: &UnitHeader<DefaultReader, usize>,
376 entry: &DebuggingInformationEntry<DefaultReader, usize>,
377) -> Result<u64, TraceError> {
378 Ok(entry
382 .required_attr(unit_header, gimli::constants::DW_AT_data_member_location)?
383 .required_udata_value()?
384 * 8)
385}
386
387fn 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 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 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 } 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
488fn 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 let location = match location {
504 Some(location) => location.value(),
505 None => return Ok(VariableLocationResult::NoLocationAttribute),
506 };
507
508 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 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 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 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(), ))?;
608 }
609 EvaluationResult::RequiresMemory {
610 address,
611 size,
612 space: None,
613 base_type: UnitOffset(0),
614 } => {
615 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
642fn 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()) .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 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
715fn 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 let variable_size_bytes = div_ceil(variable_size, 8);
737
738 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 data.append(&mut piece_data);
745 } else {
746 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
815fn 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 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 assert!(variable.front_mut().unwrap().data().name == "discriminant");
837
838 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 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 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 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 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 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 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 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 variable.data_mut().variable_value = Ok(Value::Object);
935 }
936 }
937 } else {
938 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 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 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 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 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 }
1055 Archetype::Subroutine => {
1056 variable.data_mut().variable_value = Ok(Value::Object);
1057 }
1059 Archetype::Unknown => {
1060 }
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 let variable_name = get_entry_name(dwarf, unit, entry);
1089
1090 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_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 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 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 Ok(variable_data) => read_variable_data(
1183 variable_type_value_tree.root_mut(),
1184 &variable_data,
1185 device_memory,
1186 type_cache,
1187 ),
1188 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}