1 use super::prelude::*; 2 3 // TODO?: instead of parsing lazily when invoked, parse the strings into a 4 // compressed binary representations that can be stuffed back into the packet 5 // buffer, and return an iterator over the binary data that's _guaranteed_ to be 6 // valid. This would clean up some of the code in the vCont handler. 7 // 8 // The interesting part would be to see whether or not the simplified error 9 // handing code will compensate for all the new code required to pre-validate 10 // the data... 11 #[derive(Debug)] 12 pub enum vCont<'a> { 13 Query, 14 Actions(Actions<'a>), 15 } 16 17 impl<'a> ParseCommand<'a> for vCont<'a> { from_packet(buf: PacketBuf<'a>) -> Option<Self>18 fn from_packet(buf: PacketBuf<'a>) -> Option<Self> { 19 let body = buf.into_body(); 20 match body as &[u8] { 21 b"?" => Some(vCont::Query), 22 _ => Some(vCont::Actions(Actions::new_from_buf(body))), 23 } 24 } 25 } 26 27 #[derive(Debug)] 28 pub enum Actions<'a> { 29 Buf(ActionsBuf<'a>), 30 FixedStep(SpecificThreadId), 31 FixedCont(SpecificThreadId), 32 } 33 34 impl<'a> Actions<'a> { new_from_buf(buf: &'a [u8]) -> Actions<'a>35 fn new_from_buf(buf: &'a [u8]) -> Actions<'a> { 36 Actions::Buf(ActionsBuf(buf)) 37 } 38 new_step(tid: SpecificThreadId) -> Actions<'a>39 pub fn new_step(tid: SpecificThreadId) -> Actions<'a> { 40 Actions::FixedStep(tid) 41 } 42 new_continue(tid: SpecificThreadId) -> Actions<'a>43 pub fn new_continue(tid: SpecificThreadId) -> Actions<'a> { 44 Actions::FixedCont(tid) 45 } 46 iter(&self) -> impl Iterator<Item = Option<VContAction<'a>>> + '_47 pub fn iter(&self) -> impl Iterator<Item = Option<VContAction<'a>>> + '_ { 48 match self { 49 Actions::Buf(x) => EitherIter::A(x.iter()), 50 Actions::FixedStep(x) => EitherIter::B(core::iter::once(Some(VContAction { 51 kind: VContKind::Step, 52 thread: Some(*x), 53 }))), 54 Actions::FixedCont(x) => EitherIter::B(core::iter::once(Some(VContAction { 55 kind: VContKind::Continue, 56 thread: Some(*x), 57 }))), 58 } 59 } 60 } 61 62 #[derive(Debug)] 63 pub struct ActionsBuf<'a>(&'a [u8]); 64 65 impl<'a> ActionsBuf<'a> { iter(&self) -> impl Iterator<Item = Option<VContAction<'a>>> + '_66 fn iter(&self) -> impl Iterator<Item = Option<VContAction<'a>>> + '_ { 67 self.0.split(|b| *b == b';').skip(1).map(|act| { 68 let mut s = act.split(|b| *b == b':'); 69 let kind = s.next()?; 70 let thread = match s.next() { 71 Some(s) => Some(SpecificThreadId::try_from(ThreadId::try_from(s).ok()?).ok()?), 72 None => None, 73 }; 74 75 Some(VContAction { 76 kind: VContKind::from_bytes(kind)?, 77 thread, 78 }) 79 }) 80 } 81 } 82 83 #[derive(Debug, Copy, Clone)] 84 pub struct VContAction<'a> { 85 pub kind: VContKind<'a>, 86 pub thread: Option<SpecificThreadId>, 87 } 88 89 #[derive(Debug, Copy, Clone)] 90 pub enum VContKind<'a> { 91 Continue, 92 ContinueWithSig(u8), 93 RangeStep(HexString<'a>, HexString<'a>), 94 Step, 95 StepWithSig(u8), 96 Stop, 97 } 98 99 impl<'a> VContKind<'a> { from_bytes(s: &[u8]) -> Option<VContKind>100 fn from_bytes(s: &[u8]) -> Option<VContKind> { 101 use self::VContKind::*; 102 103 let res = match s { 104 [b'c'] => Continue, 105 [b's'] => Step, 106 [b't'] => Stop, 107 [b'C', sig @ ..] => ContinueWithSig(decode_hex(sig).ok()?), 108 [b'S', sig @ ..] => StepWithSig(decode_hex(sig).ok()?), 109 [b'r', range @ ..] => { 110 let mut range = range.split(|b| *b == b','); 111 RangeStep(HexString(range.next()?), HexString(range.next()?)) 112 } 113 _ => return None, 114 }; 115 116 Some(res) 117 } 118 } 119 120 /// Helper type to unify iterators that output the same type. Returned as an 121 /// opaque type from `Actions::iter()`. 122 enum EitherIter<A, B> { 123 A(A), 124 B(B), 125 } 126 127 impl<A, B, T> Iterator for EitherIter<A, B> 128 where 129 A: Iterator<Item = T>, 130 B: Iterator<Item = T>, 131 { 132 type Item = T; next(&mut self) -> Option<T>133 fn next(&mut self) -> Option<T> { 134 match self { 135 EitherIter::A(a) => a.next(), 136 EitherIter::B(b) => b.next(), 137 } 138 } 139 } 140