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