Compare commits
2 Commits
9d37d22a22
...
16a2aaee92
Author | SHA1 | Date |
---|---|---|
|
16a2aaee92 | |
|
d59da1009a |
|
@ -311,7 +311,7 @@ impl Emulator {
|
||||||
}
|
}
|
||||||
let debug = DebugInfo {
|
let debug = DebugInfo {
|
||||||
sender,
|
sender,
|
||||||
stop_reason: Some(DebugStopReason::Trapped),
|
stop_reason: Some(DebugStopReason::Paused),
|
||||||
};
|
};
|
||||||
self.debuggers.insert(sim_id, debug);
|
self.debuggers.insert(sim_id, debug);
|
||||||
self.state
|
self.state
|
||||||
|
@ -334,7 +334,7 @@ impl Emulator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_interrupt(&mut self, sim_id: SimId) {
|
fn debug_interrupt(&mut self, sim_id: SimId) {
|
||||||
self.debug_stop(sim_id, DebugStopReason::Trapped);
|
self.debug_stop(sim_id, DebugStopReason::Paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn debug_stop(&mut self, sim_id: SimId, reason: DebugStopReason) {
|
fn debug_stop(&mut self, sim_id: SimId, reason: DebugStopReason) {
|
||||||
|
@ -686,7 +686,7 @@ pub enum DebugStopReason {
|
||||||
// We hit a watchpoint
|
// We hit a watchpoint
|
||||||
Watchpoint(VBWatchpointType, u32),
|
Watchpoint(VBWatchpointType, u32),
|
||||||
// The debugger told us to pause
|
// The debugger told us to pause
|
||||||
Trapped,
|
Paused,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DebugInfo {
|
struct DebugInfo {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -521,7 +521,11 @@ fn parse_memory_range(req: &mut Request<'_>) -> Option<(u32, usize)> {
|
||||||
|
|
||||||
fn debug_stop_reason_string(reason: Option<DebugStopReason>) -> String {
|
fn debug_stop_reason_string(reason: Option<DebugStopReason>) -> String {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
result += if reason.is_some() { "T05;" } else { "T00;" };
|
result += if reason.is_some_and(|r| r != DebugStopReason::Paused) {
|
||||||
|
"T05;"
|
||||||
|
} else {
|
||||||
|
"T00;"
|
||||||
|
};
|
||||||
if let Some(DebugStopReason::Breakpoint) = reason {
|
if let Some(DebugStopReason::Breakpoint) = reason {
|
||||||
result += "swbreak;";
|
result += "swbreak;";
|
||||||
}
|
}
|
||||||
|
@ -542,7 +546,7 @@ fn debug_stop_reason_string(reason: Option<DebugStopReason>) -> String {
|
||||||
DebugStopReason::Trace => "trace;",
|
DebugStopReason::Trace => "trace;",
|
||||||
DebugStopReason::Breakpoint => "breakpoint;",
|
DebugStopReason::Breakpoint => "breakpoint;",
|
||||||
DebugStopReason::Watchpoint(_, _) => "watchpoint;",
|
DebugStopReason::Watchpoint(_, _) => "watchpoint;",
|
||||||
DebugStopReason::Trapped => "trap;",
|
DebugStopReason::Paused => "trap;",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue