1 use super::prelude::*;
2 use crate::common::Signal;
3 use crate::protocol::common::hex::HexString;
4 use crate::protocol::common::thread_id::SpecificThreadId;
5 use crate::protocol::common::thread_id::ThreadId;
6 use crate::protocol::IdKind;
7 
8 // TODO?: instead of lazily parsing data, parse the strings into a compressed
9 // binary representations that can be stuffed back into the packet buffer and
10 // return an iterator over the binary data that's _guaranteed_ to be valid. This
11 // would clean up some of the code in the vCont handler.
12 //
13 // The interesting part would be to see whether or not the simplified error
14 // handing code will compensate for all the new code required to pre-validate
15 // the data...
16 #[derive(Debug)]
17 pub enum vCont<'a> {
18     Query,
19     Actions(Actions<'a>),
20 }
21 
22 impl<'a> ParseCommand<'a> for vCont<'a> {
23     #[inline(always)]
from_packet(buf: PacketBuf<'a>) -> Option<Self>24     fn from_packet(buf: PacketBuf<'a>) -> Option<Self> {
25         let body = buf.into_body();
26         match body as &[u8] {
27             b"?" => Some(vCont::Query),
28             _ => Some(vCont::Actions(Actions::new_from_buf(body))),
29         }
30     }
31 }
32 
33 #[derive(Debug)]
34 pub enum Actions<'a> {
35     Buf(ActionsBuf<'a>),
36     FixedStep(SpecificThreadId),
37     FixedCont(SpecificThreadId),
38 }
39 
40 impl<'a> Actions<'a> {
new_from_buf(buf: &'a [u8]) -> Actions<'a>41     fn new_from_buf(buf: &'a [u8]) -> Actions<'a> {
42         Actions::Buf(ActionsBuf(buf))
43     }
44 
45     #[inline(always)]
new_step(tid: SpecificThreadId) -> Actions<'a>46     pub fn new_step(tid: SpecificThreadId) -> Actions<'a> {
47         Actions::FixedStep(tid)
48     }
49 
50     #[inline(always)]
new_continue(tid: SpecificThreadId) -> Actions<'a>51     pub fn new_continue(tid: SpecificThreadId) -> Actions<'a> {
52         Actions::FixedCont(tid)
53     }
54 
iter(&self) -> impl Iterator<Item = Option<VContAction<'a>>> + '_55     pub fn iter(&self) -> impl Iterator<Item = Option<VContAction<'a>>> + '_ {
56         match self {
57             Actions::Buf(x) => EitherIter::A(x.iter()),
58             Actions::FixedStep(x) => EitherIter::B(core::iter::once(Some(VContAction {
59                 kind: VContKind::Step,
60                 thread: Some(*x),
61             }))),
62             Actions::FixedCont(x) => EitherIter::B(core::iter::once(Some(VContAction {
63                 kind: VContKind::Continue,
64                 thread: Some(*x),
65             }))),
66         }
67     }
68 }
69 
70 #[derive(Debug)]
71 pub struct ActionsBuf<'a>(&'a [u8]);
72 
73 impl<'a> ActionsBuf<'a> {
iter(&self) -> impl Iterator<Item = Option<VContAction<'a>>> + '_74     fn iter(&self) -> impl Iterator<Item = Option<VContAction<'a>>> + '_ {
75         self.0.split(|b| *b == b';').skip(1).map(|act| {
76             let mut s = act.split(|b| *b == b':');
77             let kind = s.next()?;
78             let thread = match s.next() {
79                 Some(s) => {
80                     let mut tid = ThreadId::try_from(s).ok()?;
81 
82                     // Based on my (somewhat superficial) readings of the
83                     // `gdbserver` and `gdb` codebases, it doesn't seem like
84                     // there's any consensus on how vCont packets with a TID of
85                     // `Any` should be be handled.
86                     //
87                     // `gdbserver` delegates the handling of this packet to
88                     // individual targets, and in-turn, it seems most targets
89                     // don't actually do any special handling of the 'Any' TID.
90                     // They'll explicitly check for the 'All' TID, but then
91                     // proceed to erroneously treat the 'Any' TID as though it
92                     // was simply a request for a TID with ID of '0' to be
93                     // resumed (which is prohibited by the GDB RSP spec).
94                     //
95                     // This behavior makes sense, given the context that AFAIK,
96                     // upstream GDB never actually sends vCont packets with a
97                     // 'Any' TID! Instead, upstream GDB will first query the
98                     // remote to obtain a list of valid TIDs, and then send over
99                     // a vCont packet with a specific TID selected.
100 
101                     // So, with all that said - how should `gdbstub` handle
102                     // these sorts of packets?
103                     //
104                     // Unfortunately, it seems like there are some weird
105                     // third-party GDB clients out there that do in-fact send an
106                     // 'Any' TID as part of a vCont packet.
107                     //
108                     // See issue #150 for more info.
109                     //
110                     // As a workaround for these weird GDB clients, `gdbstub`
111                     // takes the pragmatic approach of treating this request as
112                     // though it the client requested _all_ threads to be
113                     // resumed.
114                     //
115                     // If this turns out to be wrong... `gdbstub` can explore a
116                     // more involved fix, whereby we bubble-up this `Any`
117                     // request to the stub code itself, whereupon the stub can
118                     // attempt to pick a "reasonable" TID to individually
119                     // resume.
120                     if tid.tid == IdKind::Any {
121                         tid.tid = IdKind::All;
122                     }
123 
124                     Some(SpecificThreadId::try_from(tid).ok()?)
125                 }
126                 None => None,
127             };
128 
129             Some(VContAction {
130                 kind: VContKind::from_bytes(kind)?,
131                 thread,
132             })
133         })
134     }
135 }
136 
137 #[derive(Debug, Copy, Clone)]
138 pub struct VContAction<'a> {
139     pub kind: VContKind<'a>,
140     pub thread: Option<SpecificThreadId>,
141 }
142 
143 #[derive(Debug, Copy, Clone)]
144 pub enum VContKind<'a> {
145     Continue,
146     ContinueWithSig(Signal),
147     RangeStep(HexString<'a>, HexString<'a>),
148     Step,
149     StepWithSig(Signal),
150     Stop,
151 }
152 
153 impl<'a> VContKind<'a> {
154     #[inline(always)]
from_bytes(s: &[u8]) -> Option<VContKind<'_>>155     fn from_bytes(s: &[u8]) -> Option<VContKind<'_>> {
156         use self::VContKind::*;
157 
158         let res = match s {
159             [b'c'] => Continue,
160             [b's'] => Step,
161             [b't'] => Stop,
162             [b'C', sig @ ..] => ContinueWithSig(Signal(decode_hex(sig).ok()?)),
163             [b'S', sig @ ..] => StepWithSig(Signal(decode_hex(sig).ok()?)),
164             [b'r', range @ ..] => {
165                 let mut range = range.split(|b| *b == b',');
166                 RangeStep(HexString(range.next()?), HexString(range.next()?))
167             }
168             _ => return None,
169         };
170 
171         Some(res)
172     }
173 }
174 
175 /// Helper type to unify iterators that output the same type. Returned as an
176 /// opaque type from `Actions::iter()`.
177 enum EitherIter<A, B> {
178     A(A),
179     B(B),
180 }
181 
182 impl<A, B, T> Iterator for EitherIter<A, B>
183 where
184     A: Iterator<Item = T>,
185     B: Iterator<Item = T>,
186 {
187     type Item = T;
188 
189     #[inline(always)]
next(&mut self) -> Option<T>190     fn next(&mut self) -> Option<T> {
191         match self {
192             EitherIter::A(a) => a.next(),
193             EitherIter::B(b) => b.next(),
194         }
195     }
196 }
197