1 use super::prelude::*; 2 use crate::arch::Arch; 3 use crate::arch::BreakpointKind; 4 use crate::protocol::commands::ext::Breakpoints; 5 6 enum CmdKind { 7 Add, 8 Remove, 9 } 10 11 impl<T: Target, C: Connection> GdbStubImpl<T, C> { 12 #[inline(always)] handle_breakpoint_common( &mut self, ops: crate::target::ext::breakpoints::BreakpointsOps<'_, T>, cmd: crate::protocol::commands::breakpoint::BasicBreakpoint<'_>, cmd_kind: CmdKind, ) -> Result<HandlerStatus, Error<T::Error, C::Error>>13 fn handle_breakpoint_common( 14 &mut self, 15 ops: crate::target::ext::breakpoints::BreakpointsOps<'_, T>, 16 cmd: crate::protocol::commands::breakpoint::BasicBreakpoint<'_>, 17 cmd_kind: CmdKind, 18 ) -> Result<HandlerStatus, Error<T::Error, C::Error>> { 19 let addr = 20 <T::Arch as Arch>::Usize::from_be_bytes(cmd.addr).ok_or(Error::TargetMismatch)?; 21 22 macro_rules! bp_kind { 23 () => { 24 BeBytes::from_be_bytes(cmd.kind) 25 .and_then(<T::Arch as Arch>::BreakpointKind::from_usize) 26 .ok_or(Error::TargetMismatch)? 27 }; 28 } 29 30 let supported = match cmd.type_ { 31 0 if ops.support_sw_breakpoint().is_some() => { 32 let ops = ops.support_sw_breakpoint().unwrap(); 33 let bp_kind = bp_kind!(); 34 match cmd_kind { 35 CmdKind::Add => ops.add_sw_breakpoint(addr, bp_kind), 36 CmdKind::Remove => ops.remove_sw_breakpoint(addr, bp_kind), 37 } 38 } 39 1 if ops.support_hw_breakpoint().is_some() => { 40 let ops = ops.support_hw_breakpoint().unwrap(); 41 let bp_kind = bp_kind!(); 42 match cmd_kind { 43 CmdKind::Add => ops.add_hw_breakpoint(addr, bp_kind), 44 CmdKind::Remove => ops.remove_hw_breakpoint(addr, bp_kind), 45 } 46 } 47 2 | 3 | 4 if ops.support_hw_watchpoint().is_some() => { 48 use crate::target::ext::breakpoints::WatchKind; 49 let kind = match cmd.type_ { 50 2 => WatchKind::Write, 51 3 => WatchKind::Read, 52 4 => WatchKind::ReadWrite, 53 #[allow(clippy::unreachable)] // will be optimized out 54 _ => unreachable!(), 55 }; 56 let len = <T::Arch as Arch>::Usize::from_be_bytes(cmd.kind) 57 .ok_or(Error::TargetMismatch)?; 58 let ops = ops.support_hw_watchpoint().unwrap(); 59 match cmd_kind { 60 CmdKind::Add => ops.add_hw_watchpoint(addr, len, kind), 61 CmdKind::Remove => ops.remove_hw_watchpoint(addr, len, kind), 62 } 63 } 64 // explicitly handle unguarded variants of known breakpoint types 65 0 | 1 | 2 | 3 | 4 => return Ok(HandlerStatus::Handled), 66 // warn if the GDB client ever sends a type outside the known types 67 other => { 68 warn!("unknown breakpoint type: {}", other); 69 return Ok(HandlerStatus::Handled); 70 } 71 }; 72 73 match supported.handle_error()? { 74 true => Ok(HandlerStatus::NeedsOk), 75 false => Err(Error::NonFatalError(22)), 76 } 77 } 78 handle_breakpoints( &mut self, _res: &mut ResponseWriter<'_, C>, target: &mut T, command: Breakpoints<'_>, ) -> Result<HandlerStatus, Error<T::Error, C::Error>>79 pub(crate) fn handle_breakpoints( 80 &mut self, 81 _res: &mut ResponseWriter<'_, C>, 82 target: &mut T, 83 command: Breakpoints<'_>, 84 ) -> Result<HandlerStatus, Error<T::Error, C::Error>> { 85 let ops = match target.support_breakpoints() { 86 Some(ops) => ops, 87 None => return Ok(HandlerStatus::Handled), 88 }; 89 90 crate::__dead_code_marker!("breakpoints", "impl"); 91 92 let handler_status = match command { 93 Breakpoints::z(cmd) => self.handle_breakpoint_common(ops, cmd, CmdKind::Remove)?, 94 Breakpoints::Z(cmd) => self.handle_breakpoint_common(ops, cmd, CmdKind::Add)?, 95 // TODO: handle ZWithBytecode once agent expressions are implemented 96 _ => HandlerStatus::Handled, 97 }; 98 Ok(handler_status) 99 } 100 } 101