1use crate::common::Signal;
2use crate::common::Tid;
3use crate::conn::Connection;
4use crate::protocol::commands::Command;
5use crate::protocol::Packet;
6use crate::protocol::ResponseWriter;
7use crate::protocol::SpecificIdKind;
8use crate::stub::error::InternalError;
9use crate::target::Target;
10use crate::SINGLE_THREAD_TID;
11use core::marker::PhantomData;
12
13mod prelude {
17 pub(super) use crate::conn::Connection;
18 pub(super) use crate::internal::BeBytes;
19 pub(super) use crate::protocol::ResponseWriter;
20 pub(super) use crate::stub::core_impl::target_result_ext::TargetResultExt;
21 pub(super) use crate::stub::core_impl::GdbStubImpl;
22 pub(super) use crate::stub::core_impl::HandlerStatus;
23 pub(super) use crate::stub::error::InternalError as Error;
24 pub(super) use crate::target::Target;
25}
26
27mod auxv;
28mod base;
29mod breakpoints;
30mod catch_syscalls;
31mod exec_file;
32mod extended_mode;
33mod flash;
34mod host_io;
35mod libraries;
36mod lldb_register_info;
37mod memory_map;
38mod monitor_cmd;
39mod no_ack_mode;
40mod resume;
41mod reverse_exec;
42mod section_offsets;
43mod single_register_access;
44mod target_xml;
45mod thread_extra_info;
46mod tracepoints;
47mod x_upcase_packet;
48
49pub(crate) use resume::FinishExecStatus;
50
51pub(crate) mod target_result_ext {
52 use crate::stub::error::InternalError;
53 use crate::target::TargetError;
54
55 pub(super) trait TargetResultExt<V, T, C> {
58 fn handle_error(self) -> Result<V, InternalError<T, C>>;
62 }
63
64 impl<V, T, C> TargetResultExt<V, T, C> for Result<V, TargetError<T>> {
65 fn handle_error(self) -> Result<V, InternalError<T, C>> {
66 let code = match self {
67 Ok(v) => return Ok(v),
68 Err(TargetError::Fatal(e)) => return Err(InternalError::TargetError(e)),
69 Err(TargetError::NonFatal) => 121,
72 Err(TargetError::Errno(code)) => code,
73 #[cfg(feature = "std")]
74 Err(TargetError::Io(e)) => e.raw_os_error().unwrap_or(121) as u8,
75 };
76
77 Err(InternalError::NonFatalError(code))
78 }
79 }
80}
81
82#[derive(Clone, Copy, Debug, PartialEq, Eq)]
84pub enum DisconnectReason {
85 TargetExited(u8),
87 TargetTerminated(Signal),
89 Disconnect,
91 Kill,
93}
94
95pub enum State {
96 Pump,
97 DeferredStopReason,
98 CtrlCInterrupt,
99 Disconnect(DisconnectReason),
100}
101
102pub(crate) struct GdbStubImpl<T: Target, C: Connection> {
103 _target: PhantomData<T>,
104 _connection: PhantomData<C>,
105
106 current_mem_tid: Tid,
107 current_resume_tid: SpecificIdKind,
108 features: ProtocolFeatures,
109}
110
111pub enum HandlerStatus {
112 Handled,
113 NeedsOk,
114 DeferredStopReason,
115 Disconnect(DisconnectReason),
116}
117
118impl<T: Target, C: Connection> GdbStubImpl<T, C> {
119 pub fn new() -> GdbStubImpl<T, C> {
120 GdbStubImpl {
121 _target: PhantomData,
122 _connection: PhantomData,
123
124 current_mem_tid: SINGLE_THREAD_TID,
133 current_resume_tid: SpecificIdKind::WithId(SINGLE_THREAD_TID),
134 features: ProtocolFeatures::empty(),
135 }
136 }
137
138 pub fn handle_packet(
139 &mut self,
140 target: &mut T,
141 conn: &mut C,
142 packet: Packet<'_>,
143 ) -> Result<State, InternalError<T::Error, C::Error>> {
144 match packet {
145 Packet::Ack => Ok(State::Pump),
146 Packet::Nack => Err(InternalError::ClientSentNack),
147 Packet::Interrupt => {
148 debug!("<-- interrupt packet");
149 Ok(State::CtrlCInterrupt)
150 }
151 Packet::Command(command) => {
152 if !self.features.no_ack_mode() {
154 conn.write(b'+').map_err(InternalError::conn_write)?;
155 }
156
157 let mut res = ResponseWriter::new(conn, target.use_rle());
158 let disconnect_reason = match self.handle_command(&mut res, target, command) {
159 Ok(HandlerStatus::Handled) => None,
160 Ok(HandlerStatus::NeedsOk) => {
161 res.write_str("OK")?;
162 None
163 }
164 Ok(HandlerStatus::DeferredStopReason) => return Ok(State::DeferredStopReason),
165 Ok(HandlerStatus::Disconnect(reason)) => Some(reason),
166 Err(InternalError::NonFatalError(code)) => {
169 res.write_str("E")?;
170 res.write_num(code)?;
171 None
172 }
173 Err(e) => return Err(e),
174 };
175
176 let is_kill = matches!(disconnect_reason, Some(DisconnectReason::Kill));
179 if !(target.support_extended_mode().is_none() && is_kill) {
180 res.flush()?;
181 }
182
183 let state = match disconnect_reason {
184 Some(reason) => State::Disconnect(reason),
185 None => State::Pump,
186 };
187
188 Ok(state)
189 }
190 }
191 }
192
193 fn handle_command(
194 &mut self,
195 res: &mut ResponseWriter<'_, C>,
196 target: &mut T,
197 cmd: Command<'_>,
198 ) -> Result<HandlerStatus, InternalError<T::Error, C::Error>> {
199 match cmd {
200 Command::Base(cmd) => self.handle_base(res, target, cmd),
202 Command::TargetXml(cmd) => self.handle_target_xml(res, target, cmd),
203 Command::Resume(cmd) => self.handle_stop_resume(res, target, cmd),
204 Command::NoAckMode(cmd) => self.handle_no_ack_mode(res, target, cmd),
205 Command::XUpcasePacket(cmd) => self.handle_x_upcase_packet(res, target, cmd),
206 Command::SingleRegisterAccess(cmd) => {
207 self.handle_single_register_access(res, target, cmd)
208 }
209 Command::Breakpoints(cmd) => self.handle_breakpoints(res, target, cmd),
210 Command::CatchSyscalls(cmd) => self.handle_catch_syscalls(res, target, cmd),
211 Command::ExtendedMode(cmd) => self.handle_extended_mode(res, target, cmd),
212 Command::MonitorCmd(cmd) => self.handle_monitor_cmd(res, target, cmd),
213 Command::SectionOffsets(cmd) => self.handle_section_offsets(res, target, cmd),
214 Command::ReverseCont(cmd) => self.handle_reverse_cont(res, target, cmd),
215 Command::ReverseStep(cmd) => self.handle_reverse_step(res, target, cmd),
216 Command::MemoryMap(cmd) => self.handle_memory_map(res, target, cmd),
217 Command::FlashOperations(cmd) => self.handle_flash_operations(res, target, cmd),
218 Command::HostIo(cmd) => self.handle_host_io(res, target, cmd),
219 Command::ExecFile(cmd) => self.handle_exec_file(res, target, cmd),
220 Command::Auxv(cmd) => self.handle_auxv(res, target, cmd),
221 Command::ThreadExtraInfo(cmd) => self.handle_thread_extra_info(res, target, cmd),
222 Command::LldbRegisterInfo(cmd) => self.handle_lldb_register_info(res, target, cmd),
223 Command::LibrariesSvr4(cmd) => self.handle_libraries_svr4(res, target, cmd),
224 Command::Tracepoints(cmd) => self.handle_tracepoints(res, target, cmd),
225 Command::Unknown(cmd) => {
227 if target.base_ops().resume_ops().is_none() && target.use_resume_stub() {
231 let is_resume_pkt = cmd
232 .first()
233 .map(|c| matches!(c, b'c' | b'C' | b's' | b'S'))
234 .unwrap_or(false);
235
236 if is_resume_pkt {
237 warn!("attempted to resume target without resume support!");
238
239 {
241 let mut res = ResponseWriter::new(res.as_conn(), target.use_rle());
242 res.write_str("O")?;
243 res.write_hex_buf(b"target has not implemented `support_resume()`\n")?;
244 res.flush()?;
245 }
246
247 res.write_str("S05")?;
248 }
249 }
250
251 info!("Unknown command: {:?}", core::str::from_utf8(cmd));
252 Ok(HandlerStatus::Handled)
253 }
254 }
255 }
256}
257
258#[derive(Copy, Clone)]
259#[repr(transparent)]
260struct ProtocolFeatures(u8);
261
262bitflags::bitflags! {
266 impl ProtocolFeatures: u8 {
267 const NO_ACK_MODE = 1 << 0;
268 const MULTIPROCESS = 1 << 1;
269 }
270}
271
272impl ProtocolFeatures {
273 #[inline(always)]
274 fn no_ack_mode(&self) -> bool {
275 self.contains(ProtocolFeatures::NO_ACK_MODE)
276 }
277
278 #[inline(always)]
279 fn set_no_ack_mode(&mut self, val: bool) {
280 self.set(ProtocolFeatures::NO_ACK_MODE, val)
281 }
282
283 #[inline(always)]
284 fn multiprocess(&self) -> bool {
285 self.contains(ProtocolFeatures::MULTIPROCESS)
286 }
287
288 #[inline(always)]
289 fn set_multiprocess(&mut self, val: bool) {
290 self.set(ProtocolFeatures::MULTIPROCESS, val)
291 }
292}