use gdbstub::common::Pid; use gdbstub::target; use gdbstub::target::ext::extended_mode::{Args, ShouldTerminate}; use gdbstub::target::TargetResult; use crate::emu::Emu; /*===================================== = Extended Mode = =====================================*/ // This is a stub implementation of GDB's Extended Mode extensions. // // Truth be told, this particular emulator is _not_ very well suited to running // in extended mode, as it doesn't technically spawn/attach to any process. // Nonetheless, it's useful to have a stubbed implementation in-tree which can // be used for basic usability / regression testing. // // If you happen to implement a "proper" extended mode gdbstub, feel free to // file an issue / open a PR that links to your project! impl target::ext::extended_mode::ExtendedMode for Emu { fn kill(&mut self, pid: Option) -> TargetResult { eprintln!("GDB sent a kill request for pid {:?}", pid); Ok(ShouldTerminate::No) } fn restart(&mut self) -> Result<(), Self::Error> { eprintln!("GDB sent a restart request"); Ok(()) } fn attach(&mut self, pid: Pid) -> TargetResult<(), Self> { eprintln!("GDB tried to attach to a process with PID {}", pid); Err(().into()) // non-specific failure } fn run(&mut self, filename: Option<&[u8]>, args: Args) -> TargetResult { // simplified example: assume UTF-8 filenames / args // // To be 100% pedantically correct, consider converting to an `OsStr` in the // least lossy way possible (e.g: using the `from_bytes` extension from // `std::os::unix::ffi::OsStrExt`). let filename = match filename { None => None, Some(raw) => Some(core::str::from_utf8(raw).map_err(drop)?), }; let args = args .map(|raw| core::str::from_utf8(raw).map_err(drop)) .collect::, _>>()?; eprintln!( "GDB tried to run a new process with filename {:?}, and args {:?}", filename, args ); self.reset(); // when running in single-threaded mode, this PID can be anything Ok(Pid::new(1337).unwrap()) } fn configure_aslr(&mut self) -> Option> { Some(self) } fn configure_env(&mut self) -> Option> { Some(self) } fn configure_startup_shell( &mut self, ) -> Option> { Some(self) } fn configure_working_dir( &mut self, ) -> Option> { Some(self) } } impl target::ext::extended_mode::ConfigureASLR for Emu { fn cfg_aslr(&mut self, enabled: bool) -> TargetResult<(), Self> { eprintln!("GDB {} ASLR", if enabled { "enabled" } else { "disabled" }); Ok(()) } } impl target::ext::extended_mode::ConfigureEnv for Emu { fn set_env(&mut self, key: &[u8], val: Option<&[u8]>) -> TargetResult<(), Self> { // simplified example: assume UTF-8 key/val env vars let key = core::str::from_utf8(key).map_err(drop)?; let val = match val { None => None, Some(raw) => Some(core::str::from_utf8(raw).map_err(drop)?), }; eprintln!("GDB tried to set a new env var: {:?}={:?}", key, val); Ok(()) } fn remove_env(&mut self, key: &[u8]) -> TargetResult<(), Self> { let key = core::str::from_utf8(key).map_err(drop)?; eprintln!("GDB tried to set remove a env var: {:?}", key); Ok(()) } fn reset_env(&mut self) -> TargetResult<(), Self> { eprintln!("GDB tried to reset env vars"); Ok(()) } } impl target::ext::extended_mode::ConfigureStartupShell for Emu { fn cfg_startup_with_shell(&mut self, enabled: bool) -> TargetResult<(), Self> { eprintln!( "GDB {} startup with shell", if enabled { "enabled" } else { "disabled" } ); Ok(()) } } impl target::ext::extended_mode::ConfigureWorkingDir for Emu { fn cfg_working_dir(&mut self, dir: Option<&[u8]>) -> TargetResult<(), Self> { let dir = match dir { None => None, Some(raw) => Some(core::str::from_utf8(raw).map_err(drop)?), }; match dir { None => eprintln!("GDB reset the working directory"), Some(dir) => eprintln!("GDB set the working directory to {:?}", dir), } Ok(()) } }