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