Fix watchpoint reporting
This commit is contained in:
parent
9d37d22a22
commit
d59da1009a
|
@ -1,11 +1,11 @@
|
|||
use std::{
|
||||
collections::{BTreeMap, HashSet},
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
ops::Bound,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AddressSet {
|
||||
ranges: HashSet<(u32, usize)>,
|
||||
ranges: BTreeSet<(u32, usize)>,
|
||||
bounds: BTreeMap<u32, usize>,
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,22 @@ impl AddressSet {
|
|||
.next_back()
|
||||
.is_some_and(|(_, &val)| val > 0)
|
||||
}
|
||||
|
||||
pub fn start_of_range_containing(&self, address: u32) -> Option<u32> {
|
||||
if !self.contains(address) {
|
||||
return None;
|
||||
}
|
||||
self.ranges
|
||||
.range(..=(address, usize::MAX))
|
||||
.rev()
|
||||
.find_map(|&(start, length)| {
|
||||
let contains = start <= address
|
||||
&& (start as usize)
|
||||
.checked_add(length)
|
||||
.is_none_or(|end| end > address as usize);
|
||||
contains.then_some(start)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -120,6 +136,7 @@ mod tests {
|
|||
let set = AddressSet::new();
|
||||
assert!(set.is_empty());
|
||||
assert!(!set.contains(0x13374200));
|
||||
assert_eq!(set.start_of_range_containing(0x13374200), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -127,6 +144,7 @@ mod tests {
|
|||
let mut set = AddressSet::new();
|
||||
set.add(0x00000000, 0x100000000);
|
||||
assert!(set.contains(0x13374200));
|
||||
assert_eq!(set.start_of_range_containing(0x13374200), Some(0x00000000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -228,4 +246,25 @@ mod tests {
|
|||
assert!(!set.contains(address));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_find_start_of_range() {
|
||||
let mut set = AddressSet::new();
|
||||
set.add(0x13374200, 4);
|
||||
assert_eq!(set.start_of_range_containing(0x133741ff), None);
|
||||
for address in 0x13374200..0x13374204 {
|
||||
assert_eq!(set.start_of_range_containing(address), Some(0x13374200));
|
||||
}
|
||||
assert_eq!(set.start_of_range_containing(0x13374204), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_ignore_ranges_not_containing_address() {
|
||||
let mut set = AddressSet::new();
|
||||
set.add(0x10000000, 1024);
|
||||
set.add(0x30000000, 1024);
|
||||
|
||||
assert!(!set.contains(0x20000000));
|
||||
assert_eq!(set.start_of_range_containing(0x20000000), None);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -215,13 +215,13 @@ extern "C" fn on_read(
|
|||
// There is no way for the userdata to be null or otherwise invalid.
|
||||
let data: &mut VBState = unsafe { &mut *vb_get_user_data(sim).cast() };
|
||||
|
||||
if data.read_watchpoints.contains(address) {
|
||||
if let Some(start) = data.read_watchpoints.start_of_range_containing(address) {
|
||||
let watch = if data.write_watchpoints.contains(address) {
|
||||
VBWatchpointType::Access
|
||||
} else {
|
||||
VBWatchpointType::Read
|
||||
};
|
||||
data.stop_reason = Some(StopReason::Watchpoint(watch, address));
|
||||
data.stop_reason = Some(StopReason::Watchpoint(watch, start));
|
||||
}
|
||||
|
||||
// Don't stop here, the debugger expects us to break after the memory access.
|
||||
|
@ -242,13 +242,13 @@ extern "C" fn on_write(
|
|||
// There is no way for the userdata to be null or otherwise invalid.
|
||||
let data: &mut VBState = unsafe { &mut *vb_get_user_data(sim).cast() };
|
||||
|
||||
if data.write_watchpoints.contains(address) {
|
||||
if let Some(start) = data.write_watchpoints.start_of_range_containing(address) {
|
||||
let watch = if data.read_watchpoints.contains(address) {
|
||||
VBWatchpointType::Access
|
||||
} else {
|
||||
VBWatchpointType::Write
|
||||
};
|
||||
data.stop_reason = Some(StopReason::Watchpoint(watch, address));
|
||||
data.stop_reason = Some(StopReason::Watchpoint(watch, start));
|
||||
}
|
||||
|
||||
// Don't stop here, the debugger expects us to break after the memory access.
|
||||
|
|
Loading…
Reference in New Issue