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