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