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