-
-
Notifications
You must be signed in to change notification settings - Fork 62
Description
I used gdbstub to create an on-device embedded debugger (in which it is working very well), but initially setting up the integration felt like I was working around the borrow-check system. The crate's packet buffer API seems to be optimized for having a function-scoped GdbStub that refers to existing data structures, whereas I need my debugger to live for the entire program with the ability to be periodically polled from any context.
Since my GdbStub instance needs to be stored globally, I need it to be 'static. However, there's no option for it to own its packet buffer; it only accepts references. Attaining such a &'static mut [u8] required me to do some unsafe shenanigans:
pub struct V5Debugger<S: Connection + ConnectionExt> {
target: V5Target,
gdb: Option<GdbStubStateMachine<'static, V5Target, S>>,
}
const GDB_PACKET_BUFFER_SIZE: usize = 0x2000;
static mut GDB_PACKET_BUFFER: [u8; GDB_PACKET_BUFFER_SIZE] = [0; _];
static GDB_PACKET_BUFFER_CLAIMED: AtomicBool = AtomicBool::new(false);
if GDB_PACKET_BUFFER_CLAIMED.swap(true, Ordering::Acquire) {
panic!("Cannot create multiple debuggers");
}
// SAFETY: The mutable ownership over the buffer can only be taken once.
let gdb_buffer: &'static mut [u8] = unsafe {
core::slice::from_raw_parts_mut(&raw mut GDB_PACKET_BUFFER[0], GDB_PACKET_BUFFER_SIZE)
};
let mut target = V5Target::new();
Self {
gdb: {
let stub = GdbStubBuilder::new(stream)
.with_packet_buffer(gdb_buffer)
.build()
.unwrap();
Some(stub.run_state_machine(&mut target).unwrap())
},
target,
}It would be very convenient if I didn't have to worry about GDBStub's packet buffer. I'd be happy to do something like this:
const GDB_PACKET_BUFFER_SIZE: usize = 0x2000;
let mut target = V5Target::new();
Self {
gdb: {
let stub = StaticGdbStub::<GDB_PACKET_BUFFER_SIZE>::new(stream);
Some(stub.run_state_machine(&mut target).unwrap())
},
target,
}...or have some other API that implements the buffer as an owned array.