1 use crate::protocol::common::hex::decode_hex;
2 use crate::protocol::common::hex::decode_hex_buf;
3
4 // Breakpoint packets are split up like this:
5 //
6 // Z0,addr,kind[;cond_list…][;cmds:persist,cmd_list…]
7 // \_________/
8 // |
9 // BasicBreakpoint
10 // \_______________________________________________/
11 // |
12 // BytecodeBreakpoint
13 //
14 // If the target does not implement the `Agent` extension, only the
15 // `BasicBreakpoint` part is parsed, which helps cut down on binary bloat.
16
17 #[derive(Debug)]
18 pub struct BasicBreakpoint<'a> {
19 pub type_: u8,
20 pub addr: &'a [u8],
21 /// architecture dependent
22 pub kind: &'a [u8],
23 }
24
25 impl<'a> BasicBreakpoint<'a> {
from_slice(body: &'a mut [u8]) -> Option<BasicBreakpoint<'a>>26 pub fn from_slice(body: &'a mut [u8]) -> Option<BasicBreakpoint<'a>> {
27 let mut body = body.splitn_mut(4, |b| matches!(*b, b',' | b';'));
28 let type_ = decode_hex(body.next()?).ok()?;
29 let addr = decode_hex_buf(body.next()?).ok()?;
30 let kind = decode_hex_buf(body.next()?).ok()?;
31
32 Some(BasicBreakpoint { type_, addr, kind })
33 }
34 }
35
36 #[derive(Debug)]
37 pub struct BytecodeBreakpoint<'a> {
38 pub base: BasicBreakpoint<'a>,
39 pub conds: Option<BytecodeList<'a>>,
40 pub cmds_persist: Option<(BytecodeList<'a>, bool)>,
41 }
42
43 impl<'a> BytecodeBreakpoint<'a> {
from_slice(body: &'a mut [u8]) -> Option<BytecodeBreakpoint<'a>>44 pub fn from_slice(body: &'a mut [u8]) -> Option<BytecodeBreakpoint<'a>> {
45 let mut body = body.splitn_mut(2, |b| *b == b';');
46
47 let base = BasicBreakpoint::from_slice(body.next()?)?;
48
49 let mut conds = None;
50 let mut cmds_persist = None;
51
52 if let Some(rest) = body.next() {
53 let mut s = rest.split_mut(|b| *b == b':');
54 let (raw_conds, raw_cmds) = match (s.next(), s.next()) {
55 (Some(a), Some(b)) => (Some(strip_suffix_mut(a, b";cmds")?), Some(b)),
56 (Some(a), None) => {
57 if a.starts_with(b"cmds") {
58 (None, Some(a))
59 } else {
60 (Some(a), None)
61 }
62 }
63 _ => return None,
64 };
65
66 if let Some(raw_conds) = raw_conds {
67 conds = Some(BytecodeList(raw_conds));
68 }
69
70 if let Some(raw_cmds) = raw_cmds {
71 let mut raw_cmds = raw_cmds.split_mut(|b| *b == b',');
72 let raw_persist = decode_hex::<u8>(raw_cmds.next()?).ok()? != 0;
73 let raw_cmds = raw_cmds.next()?;
74
75 cmds_persist = Some((BytecodeList(raw_cmds), raw_persist));
76 }
77 }
78
79 Some(BytecodeBreakpoint {
80 base,
81 conds,
82 cmds_persist,
83 })
84 }
85 }
86
strip_suffix_mut<'a, T>(slice: &'a mut [T], suffix: &[T]) -> Option<&'a mut [T]> where T: PartialEq,87 fn strip_suffix_mut<'a, T>(slice: &'a mut [T], suffix: &[T]) -> Option<&'a mut [T]>
88 where
89 T: PartialEq,
90 {
91 let (len, n) = (slice.len(), suffix.len());
92 if n <= len {
93 let (head, tail) = slice.split_at_mut(len - n);
94 if tail == suffix {
95 return Some(head);
96 }
97 }
98 None
99 }
100
101 /// A lazily evaluated iterator over a series of bytecode expressions.
102 #[derive(Debug)]
103 pub struct BytecodeList<'a>(&'a mut [u8]);
104
105 impl<'a> BytecodeList<'a> {
106 #[allow(dead_code)]
into_iter(self) -> impl Iterator<Item = Option<&'a [u8]>> + 'a107 pub fn into_iter(self) -> impl Iterator<Item = Option<&'a [u8]>> + 'a {
108 self.0.split_mut(|b| *b == b'X').skip(1).map(|s| {
109 let mut s = s.split_mut(|b| *b == b',');
110 let _len = s.next()?;
111 let code = decode_hex_buf(s.next()?).ok()?;
112 Some(code as &[u8])
113 })
114 }
115 }
116