use crate::protocol::common::hex::decode_hex; use crate::protocol::common::hex::decode_hex_buf; // Breakpoint packets are split up like this: // // Z0,addr,kind[;cond_list…][;cmds:persist,cmd_list…] // \_________/ // | // BasicBreakpoint // \_______________________________________________/ // | // BytecodeBreakpoint // // If the target does not implement the `Agent` extension, only the // `BasicBreakpoint` part is parsed, which helps cut down on binary bloat. #[derive(Debug)] pub struct BasicBreakpoint<'a> { pub type_: u8, pub addr: &'a [u8], /// architecture dependent pub kind: &'a [u8], } impl<'a> BasicBreakpoint<'a> { pub fn from_slice(body: &'a mut [u8]) -> Option> { let mut body = body.splitn_mut(4, |b| matches!(*b, b',' | b';')); let type_ = decode_hex(body.next()?).ok()?; let addr = decode_hex_buf(body.next()?).ok()?; let kind = decode_hex_buf(body.next()?).ok()?; Some(BasicBreakpoint { type_, addr, kind }) } } #[allow(dead_code)] // Bytecode hasn't yet been plumbed all the way through #[derive(Debug)] pub struct BytecodeBreakpoint<'a> { pub base: BasicBreakpoint<'a>, pub conds: Option>, pub cmds_persist: Option<(BytecodeList<'a>, bool)>, } impl<'a> BytecodeBreakpoint<'a> { pub fn from_slice(body: &'a mut [u8]) -> Option> { let mut body = body.splitn_mut(2, |b| *b == b';'); let base = BasicBreakpoint::from_slice(body.next()?)?; let mut conds = None; let mut cmds_persist = None; if let Some(rest) = body.next() { let mut s = rest.split_mut(|b| *b == b':'); let (raw_conds, raw_cmds) = match (s.next(), s.next()) { (Some(a), Some(b)) => (Some(strip_suffix_mut(a, b";cmds")?), Some(b)), (Some(a), None) => { if a.starts_with(b"cmds") { (None, Some(a)) } else { (Some(a), None) } } _ => return None, }; if let Some(raw_conds) = raw_conds { conds = Some(BytecodeList(raw_conds)); } if let Some(raw_cmds) = raw_cmds { let mut raw_cmds = raw_cmds.split_mut(|b| *b == b','); let raw_persist = decode_hex::(raw_cmds.next()?).ok()? != 0; let raw_cmds = raw_cmds.next()?; cmds_persist = Some((BytecodeList(raw_cmds), raw_persist)); } } Some(BytecodeBreakpoint { base, conds, cmds_persist, }) } } fn strip_suffix_mut<'a, T>(slice: &'a mut [T], suffix: &[T]) -> Option<&'a mut [T]> where T: PartialEq, { let (len, n) = (slice.len(), suffix.len()); if n <= len { let (head, tail) = slice.split_at_mut(len - n); if tail == suffix { return Some(head); } } None } /// A lazily evaluated iterator over a series of bytecode expressions. #[derive(Debug)] pub struct BytecodeList<'a>(&'a mut [u8]); impl<'a> BytecodeList<'a> { #[allow(dead_code)] pub fn into_iter(self) -> impl Iterator> + 'a { self.0.split_mut(|b| *b == b'X').skip(1).map(|s| { let mut s = s.split_mut(|b| *b == b','); let _len = s.next()?; let code = decode_hex_buf(s.next()?).ok()?; Some(code as &[u8]) }) } }