Fix watchpoint reporting
This commit is contained in:
		
							parent
							
								
									9d37d22a22
								
							
						
					
					
						commit
						d59da1009a
					
				| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    collections::{BTreeMap, HashSet},
 | 
					    collections::{BTreeMap, BTreeSet},
 | 
				
			||||||
    ops::Bound,
 | 
					    ops::Bound,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Default)]
 | 
					#[derive(Debug, Default)]
 | 
				
			||||||
pub struct AddressSet {
 | 
					pub struct AddressSet {
 | 
				
			||||||
    ranges: HashSet<(u32, usize)>,
 | 
					    ranges: BTreeSet<(u32, usize)>,
 | 
				
			||||||
    bounds: BTreeMap<u32, usize>,
 | 
					    bounds: BTreeMap<u32, usize>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -109,6 +109,22 @@ impl AddressSet {
 | 
				
			||||||
            .next_back()
 | 
					            .next_back()
 | 
				
			||||||
            .is_some_and(|(_, &val)| val > 0)
 | 
					            .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)]
 | 
					#[cfg(test)]
 | 
				
			||||||
| 
						 | 
					@ -120,6 +136,7 @@ mod tests {
 | 
				
			||||||
        let set = AddressSet::new();
 | 
					        let set = AddressSet::new();
 | 
				
			||||||
        assert!(set.is_empty());
 | 
					        assert!(set.is_empty());
 | 
				
			||||||
        assert!(!set.contains(0x13374200));
 | 
					        assert!(!set.contains(0x13374200));
 | 
				
			||||||
 | 
					        assert_eq!(set.start_of_range_containing(0x13374200), None);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
| 
						 | 
					@ -127,6 +144,7 @@ mod tests {
 | 
				
			||||||
        let mut set = AddressSet::new();
 | 
					        let mut set = AddressSet::new();
 | 
				
			||||||
        set.add(0x00000000, 0x100000000);
 | 
					        set.add(0x00000000, 0x100000000);
 | 
				
			||||||
        assert!(set.contains(0x13374200));
 | 
					        assert!(set.contains(0x13374200));
 | 
				
			||||||
 | 
					        assert_eq!(set.start_of_range_containing(0x13374200), Some(0x00000000));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
| 
						 | 
					@ -228,4 +246,25 @@ mod tests {
 | 
				
			||||||
            assert!(!set.contains(address));
 | 
					            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.
 | 
					    // 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() };
 | 
					    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) {
 | 
					        let watch = if data.write_watchpoints.contains(address) {
 | 
				
			||||||
            VBWatchpointType::Access
 | 
					            VBWatchpointType::Access
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            VBWatchpointType::Read
 | 
					            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.
 | 
					    // 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.
 | 
					    // 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() };
 | 
					    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) {
 | 
					        let watch = if data.read_watchpoints.contains(address) {
 | 
				
			||||||
            VBWatchpointType::Access
 | 
					            VBWatchpointType::Access
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            VBWatchpointType::Write
 | 
					            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.
 | 
					    // Don't stop here, the debugger expects us to break after the memory access.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue