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