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