rust_debug/utils.rs
1use gimli::{
2 DebuggingInformationEntry, Dwarf, Error, Range, RangeIter, Reader, Unit, UnitOffset,
3 UnitSectionOffset,
4};
5use log::error;
6
7pub struct DwarfOffset {
8 pub section_offset: UnitSectionOffset,
9 pub unit_offset: UnitOffset,
10}
11
12/// Check if the given address is withing range of any of the given ranges.
13///
14/// Description:
15///
16/// * `pc` - A 32 bit machine code address, which is most commonly the current program counter value.
17/// * `rang` - A iterator over machine code address ranges.
18///
19/// It checks if the given address is within the range of each given address ranges.
20/// If the address is in range of one of them then it will return `Some(true)`, otherwise it will return
21/// `Some(false)`.
22/// The function will only return `None` if the address range iterator does not contain any address
23/// ranges.
24pub fn in_ranges<R>(pc: u32, rang: &mut RangeIter<R>) -> Option<bool>
25where
26 R: Reader<Offset = usize>,
27{
28 let mut no_range = true;
29 while let Ok(Some(range)) = rang.next() {
30 if in_range(pc, &range) {
31 return Some(true);
32 }
33 no_range = false;
34 }
35 if no_range {
36 return None;
37 }
38 Some(false)
39}
40
41/// Check if the given address is withing a range of addresses.
42///
43/// Description:
44///
45/// * `pc` - A 32 bit machine code address, which is most commonly the current program counter value.
46/// * `range` - A reference to a machine code address range.
47///
48/// It checks if the given address is within the range of machine code addresses.
49/// If the address is in range it will return `true`, otherwise `false`.
50/// return false.
51pub fn in_range(pc: u32, range: &Range) -> bool {
52 range.begin <= pc as u64 && range.end > pc as u64
53}
54
55/// Check if the given address is withing a DIEs address range.
56///
57/// Description:
58///
59/// * `dwarf` - A reference to gimli-rs Dwarf struct.
60/// * `unit` - A reference to a gimli-rs Unit struct, which contains the DIE to check.
61/// * `die` - A reference to a gimli-rs Die struct that will be checked.
62/// * `pc` - A 32 bit machine code address, which is most commonly the current program counter value.
63///
64/// It checks if the given address is within the address range of the given DIE.
65/// If the address is in range it will return `Some(true)`, otherwise it will return `Some(false)`.
66/// If the DIE has no address ranges it will return `None`.
67pub fn die_in_range<'a, R>(
68 dwarf: &'a Dwarf<R>,
69 unit: &'a Unit<R>,
70 die: &DebuggingInformationEntry<'_, '_, R>,
71 pc: u32,
72) -> Option<bool>
73where
74 R: Reader<Offset = usize>,
75{
76 match dwarf.die_ranges(unit, die) {
77 Ok(mut range) => in_ranges(pc, &mut range),
78 Err(_) => None,
79 }
80}
81
82/// Find a compilation unit(gimli-rs Unit) using a address.
83///
84/// Description:
85///
86/// * `dwarf` - A reference to gimli-rs Dwarf struct.
87/// * `pc` - A 32 bit machine code address, which is most commonly the current program counter value.
88///
89/// This function will check if the given address is within range of all the compilation units in the `.debug_info` DWARF section.
90/// If there is only one unit in range it will return it, otherwise it will return a error.
91pub fn get_current_unit<R>(dwarf: &'_ Dwarf<R>, pc: u32) -> Result<Unit<R>, Error>
92where
93 R: Reader<Offset = usize>,
94{
95 // TODO: Maybe return a Vec of units
96 let mut res = None;
97
98 let mut iter = dwarf.units();
99 let mut i = 0;
100 while let Some(header) = iter.next()? {
101 let unit = dwarf.unit(header)?;
102 if Some(true) == in_ranges(pc, &mut dwarf.unit_ranges(&unit)?) {
103 res = Some(unit);
104 i += 1;
105 }
106 }
107
108 if i > 1 {
109 error!("Found more then one unit in range {}", i);
110 }
111
112 match res {
113 Some(u) => Ok(u),
114 None => Err(Error::MissingUnitDie),
115 }
116}