torsh_jit/debugger/
breakpoints.rs1use super::core::{Breakpoint, BreakpointId, BreakpointLocation, ExecutionLocation};
7use crate::{JitError, JitResult};
8use std::collections::HashMap;
9
10pub struct BreakpointManager {
12 breakpoints: HashMap<BreakpointId, Breakpoint>,
13 next_id: BreakpointId,
14}
15
16impl BreakpointManager {
17 pub fn new() -> Self {
19 Self {
20 breakpoints: HashMap::new(),
21 next_id: BreakpointId(0),
22 }
23 }
24
25 pub fn set_breakpoint(&mut self, location: BreakpointLocation) -> JitResult<BreakpointId> {
43 let id = self.next_id;
44 self.next_id = BreakpointId(self.next_id.0 + 1);
45
46 let breakpoint = Breakpoint {
47 id,
48 location,
49 condition: None,
50 enabled: true,
51 hit_count: 0,
52 };
53
54 self.breakpoints.insert(id, breakpoint);
55 Ok(id)
56 }
57
58 pub fn set_conditional_breakpoint(
67 &mut self,
68 location: BreakpointLocation,
69 condition: String,
70 ) -> JitResult<BreakpointId> {
71 let id = self.next_id;
72 self.next_id = BreakpointId(self.next_id.0 + 1);
73
74 let breakpoint = Breakpoint {
75 id,
76 location,
77 condition: Some(condition),
78 enabled: true,
79 hit_count: 0,
80 };
81
82 self.breakpoints.insert(id, breakpoint);
83 Ok(id)
84 }
85
86 pub fn remove_breakpoint(&mut self, id: BreakpointId) -> JitResult<()> {
94 if self.breakpoints.remove(&id).is_some() {
95 Ok(())
96 } else {
97 Err(JitError::RuntimeError(format!(
98 "Breakpoint {} not found",
99 id.0
100 )))
101 }
102 }
103
104 pub fn enable_breakpoint(&mut self, id: BreakpointId) -> JitResult<()> {
109 if let Some(breakpoint) = self.breakpoints.get_mut(&id) {
110 breakpoint.enabled = true;
111 Ok(())
112 } else {
113 Err(JitError::RuntimeError(format!(
114 "Breakpoint {} not found",
115 id.0
116 )))
117 }
118 }
119
120 pub fn disable_breakpoint(&mut self, id: BreakpointId) -> JitResult<()> {
125 if let Some(breakpoint) = self.breakpoints.get_mut(&id) {
126 breakpoint.enabled = false;
127 Ok(())
128 } else {
129 Err(JitError::RuntimeError(format!(
130 "Breakpoint {} not found",
131 id.0
132 )))
133 }
134 }
135
136 pub fn list_breakpoints(&self) -> Vec<&Breakpoint> {
141 self.breakpoints.values().collect()
142 }
143
144 pub fn get_breakpoint(&self, id: BreakpointId) -> Option<&Breakpoint> {
152 self.breakpoints.get(&id)
153 }
154
155 pub fn is_breakpoint_at(&self, location: &ExecutionLocation) -> bool {
163 self.breakpoints.values().any(|bp| {
164 bp.enabled
165 && match (&bp.location, location) {
166 (
167 BreakpointLocation::GraphNode(bp_node),
168 ExecutionLocation::GraphNode(loc_node),
169 ) => bp_node == loc_node,
170 (
171 BreakpointLocation::Instruction {
172 function: bp_func,
173 instruction: bp_inst,
174 },
175 ExecutionLocation::Instruction {
176 function: loc_func,
177 instruction_index: loc_inst,
178 },
179 ) => bp_func == loc_func && *bp_inst == *loc_inst,
180 _ => false,
181 }
182 })
183 }
184
185 pub fn hit_breakpoints_at(&mut self, location: &ExecutionLocation) -> usize {
193 let mut hit_count = 0;
194 for breakpoint in self.breakpoints.values_mut() {
195 if breakpoint.enabled
196 && match (&breakpoint.location, location) {
197 (
198 BreakpointLocation::GraphNode(bp_node),
199 ExecutionLocation::GraphNode(loc_node),
200 ) => bp_node == loc_node,
201 (
202 BreakpointLocation::Instruction {
203 function: bp_func,
204 instruction: bp_inst,
205 },
206 ExecutionLocation::Instruction {
207 function: loc_func,
208 instruction_index: loc_inst,
209 },
210 ) => bp_func == loc_func && *bp_inst == *loc_inst,
211 _ => false,
212 }
213 {
214 breakpoint.hit_count += 1;
215 hit_count += 1;
216 }
217 }
218 hit_count
219 }
220
221 pub fn clear_all_breakpoints(&mut self) {
223 self.breakpoints.clear();
224 }
225
226 pub fn count(&self) -> usize {
228 self.breakpoints.len()
229 }
230
231 pub fn enabled_count(&self) -> usize {
233 self.breakpoints.values().filter(|bp| bp.enabled).count()
234 }
235
236 pub fn get_breakpoints_at(&self, location: &BreakpointLocation) -> Vec<&Breakpoint> {
244 self.breakpoints
245 .values()
246 .filter(|bp| match (&bp.location, location) {
247 (
248 BreakpointLocation::GraphNode(bp_node),
249 BreakpointLocation::GraphNode(loc_node),
250 ) => bp_node == loc_node,
251 (
252 BreakpointLocation::Instruction {
253 function: bp_func,
254 instruction: bp_inst,
255 },
256 BreakpointLocation::Instruction {
257 function: loc_func,
258 instruction: loc_inst,
259 },
260 ) => bp_func == loc_func && bp_inst == loc_inst,
261 _ => false,
262 })
263 .collect()
264 }
265}
266
267impl Default for BreakpointManager {
268 fn default() -> Self {
269 Self::new()
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276 use crate::NodeId;
277
278 #[test]
279 fn test_breakpoint_manager_creation() {
280 let manager = BreakpointManager::new();
281 assert_eq!(manager.count(), 0);
282 assert_eq!(manager.enabled_count(), 0);
283 }
284
285 #[test]
286 fn test_set_and_remove_breakpoint() {
287 let mut manager = BreakpointManager::new();
288
289 let location = BreakpointLocation::GraphNode(NodeId::new(0));
290 let id = manager.set_breakpoint(location).unwrap();
291
292 assert_eq!(manager.count(), 1);
293 assert_eq!(manager.enabled_count(), 1);
294 assert!(manager.remove_breakpoint(id).is_ok());
295 assert_eq!(manager.count(), 0);
296 }
297
298 #[test]
299 fn test_conditional_breakpoint() {
300 let mut manager = BreakpointManager::new();
301
302 let location = BreakpointLocation::GraphNode(NodeId::new(0));
303 let condition = "x > 10".to_string();
304 let id = manager
305 .set_conditional_breakpoint(location, condition.clone())
306 .unwrap();
307
308 let breakpoint = manager.get_breakpoint(id).unwrap();
309 assert_eq!(breakpoint.condition, Some(condition));
310 }
311
312 #[test]
313 fn test_enable_disable_breakpoint() {
314 let mut manager = BreakpointManager::new();
315
316 let location = BreakpointLocation::GraphNode(NodeId::new(0));
317 let id = manager.set_breakpoint(location).unwrap();
318
319 assert_eq!(manager.enabled_count(), 1);
320
321 manager.disable_breakpoint(id).unwrap();
322 assert_eq!(manager.enabled_count(), 0);
323
324 manager.enable_breakpoint(id).unwrap();
325 assert_eq!(manager.enabled_count(), 1);
326 }
327
328 #[test]
329 fn test_is_breakpoint_at() {
330 let mut manager = BreakpointManager::new();
331
332 let node_id = NodeId::new(0);
333 let location = BreakpointLocation::GraphNode(node_id);
334 manager.set_breakpoint(location).unwrap();
335
336 let exec_location = ExecutionLocation::GraphNode(node_id);
337 assert!(manager.is_breakpoint_at(&exec_location));
338
339 let other_exec_location = ExecutionLocation::GraphNode(NodeId::new(1));
340 assert!(!manager.is_breakpoint_at(&other_exec_location));
341 }
342
343 #[test]
344 fn test_hit_breakpoints() {
345 let mut manager = BreakpointManager::new();
346
347 let node_id = NodeId::new(0);
348 let location = BreakpointLocation::GraphNode(node_id);
349 let id = manager.set_breakpoint(location).unwrap();
350
351 let exec_location = ExecutionLocation::GraphNode(node_id);
352 let hit_count = manager.hit_breakpoints_at(&exec_location);
353 assert_eq!(hit_count, 1);
354
355 let breakpoint = manager.get_breakpoint(id).unwrap();
356 assert_eq!(breakpoint.hit_count, 1);
357 }
358
359 #[test]
360 fn test_clear_all_breakpoints() {
361 let mut manager = BreakpointManager::new();
362
363 manager
364 .set_breakpoint(BreakpointLocation::GraphNode(NodeId::new(0)))
365 .unwrap();
366 manager
367 .set_breakpoint(BreakpointLocation::GraphNode(NodeId::new(1)))
368 .unwrap();
369
370 assert_eq!(manager.count(), 2);
371 manager.clear_all_breakpoints();
372 assert_eq!(manager.count(), 0);
373 }
374}