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