1 use super::core_impl::GdbStubImpl;
2 use super::GdbStub;
3 use crate::conn::Connection;
4 use crate::target::Target;
5 use core::fmt::Display;
6 use core::fmt::{self};
7 use core::marker::PhantomData;
8 use managed::ManagedSlice;
9 
10 /// An error which may occur when building a [`GdbStub`].
11 #[derive(Debug)]
12 pub enum GdbStubBuilderError {
13     /// Must provide buffer using `with_packet_buffer` in `#![no_std]` mode.
14     MissingPacketBuffer,
15     /// Custom packet buffer size is larger than the provided buffer's length.
16     PacketBufSizeMismatch,
17 }
18 
19 impl Display for GdbStubBuilderError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result20     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21         use self::GdbStubBuilderError::*;
22         match self {
23             MissingPacketBuffer => write!(
24                 f,
25                 "Must provide buffer using `with_packet_buffer` in `#![no_std]` mode."
26             ),
27             PacketBufSizeMismatch => write!(
28                 f,
29                 "`packet_buffer_size` is larger than `with_packet_buffer`'s size."
30             ),
31         }
32     }
33 }
34 
35 #[cfg(feature = "std")]
36 impl std::error::Error for GdbStubBuilderError {}
37 
38 /// Helper to construct and customize [`GdbStub`].
39 pub struct GdbStubBuilder<'a, T: Target, C: Connection> {
40     conn: C,
41     packet_buffer: Option<&'a mut [u8]>,
42     packet_buffer_size: Option<usize>,
43 
44     _target: PhantomData<T>,
45 }
46 
47 impl<'a, T: Target, C: Connection> GdbStubBuilder<'a, T, C> {
48     /// Create a new `GdbStubBuilder` using the provided Connection.
new(conn: C) -> GdbStubBuilder<'static, T, C>49     pub fn new(conn: C) -> GdbStubBuilder<'static, T, C> {
50         GdbStubBuilder {
51             conn,
52             packet_buffer: None,
53             packet_buffer_size: None,
54 
55             _target: PhantomData,
56         }
57     }
58 
59     /// Use a pre-allocated packet buffer (instead of heap-allocating).
60     ///
61     /// _Note:_ This method is _required_ when the `alloc` feature is disabled!
with_packet_buffer(mut self, packet_buffer: &'a mut [u8]) -> Self62     pub fn with_packet_buffer(mut self, packet_buffer: &'a mut [u8]) -> Self {
63         self.packet_buffer = Some(packet_buffer);
64         self
65     }
66 
67     /// Specify a custom size for the packet buffer. Defaults to 4096 bytes.
68     ///
69     /// When used alongside `with_packet_buffer`, the provided `size` must be
70     /// less than or equal to the length of the packet buffer.
packet_buffer_size(mut self, size: usize) -> Self71     pub fn packet_buffer_size(mut self, size: usize) -> Self {
72         self.packet_buffer_size = Some(size);
73         self
74     }
75 
76     /// Build the GdbStub, returning an error if something went wrong.
build(self) -> Result<GdbStub<'a, T, C>, GdbStubBuilderError>77     pub fn build(self) -> Result<GdbStub<'a, T, C>, GdbStubBuilderError> {
78         let packet_buffer = match self.packet_buffer {
79             Some(buf) => {
80                 let buf = match self.packet_buffer_size {
81                     Some(custom_len) => {
82                         if custom_len > buf.len() {
83                             return Err(GdbStubBuilderError::PacketBufSizeMismatch);
84                         } else {
85                             &mut buf[..custom_len]
86                         }
87                     }
88                     None => buf,
89                 };
90                 ManagedSlice::Borrowed(buf)
91             }
92             None => {
93                 cfg_if::cfg_if! {
94                     if #[cfg(feature = "alloc")] {
95                         use alloc::vec;
96                         // need to pick some arbitrary value to report to GDB
97                         // 4096 seems reasonable?
98                         let len = self.packet_buffer_size.unwrap_or(4096);
99                         ManagedSlice::Owned(vec![0; len])
100                     } else {
101                         return Err(GdbStubBuilderError::MissingPacketBuffer);
102                     }
103                 }
104             }
105         };
106 
107         Ok(GdbStub {
108             conn: self.conn,
109             packet_buffer,
110             inner: GdbStubImpl::new(),
111         })
112     }
113 }
114