1 use gdbstub::common::Pid; 2 use gdbstub::target; 3 use gdbstub::target::ext::extended_mode::{Args, ShouldTerminate}; 4 use gdbstub::target::TargetResult; 5 6 use crate::emu::Emu; 7 8 /*===================================== 9 = Extended Mode = 10 =====================================*/ 11 12 // This is a stub implementation of GDB's Extended Mode extensions. 13 // 14 // Truth be told, this particular emulator is _not_ very well suited to running 15 // in extended mode, as it doesn't technically spawn/attach to any process. 16 // Nonetheless, it's useful to have a stubbed implementation in-tree which can 17 // be used for basic usability / regression testing. 18 // 19 // If you happen to implement a "proper" extended mode gdbstub, feel free to 20 // file an issue / open a PR that links to your project! 21 22 impl target::ext::extended_mode::ExtendedMode for Emu { kill(&mut self, pid: Option<Pid>) -> TargetResult<ShouldTerminate, Self>23 fn kill(&mut self, pid: Option<Pid>) -> TargetResult<ShouldTerminate, Self> { 24 eprintln!("GDB sent a kill request for pid {:?}", pid); 25 Ok(ShouldTerminate::No) 26 } 27 restart(&mut self) -> Result<(), Self::Error>28 fn restart(&mut self) -> Result<(), Self::Error> { 29 eprintln!("GDB sent a restart request"); 30 Ok(()) 31 } 32 attach(&mut self, pid: Pid) -> TargetResult<(), Self>33 fn attach(&mut self, pid: Pid) -> TargetResult<(), Self> { 34 eprintln!("GDB tried to attach to a process with PID {}", pid); 35 Err(().into()) // non-specific failure 36 } 37 run(&mut self, filename: Option<&[u8]>, args: Args) -> TargetResult<Pid, Self>38 fn run(&mut self, filename: Option<&[u8]>, args: Args) -> TargetResult<Pid, Self> { 39 // simplified example: assume UTF-8 filenames / args 40 // 41 // To be 100% pedantically correct, consider converting to an `OsStr` in the 42 // least lossy way possible (e.g: using the `from_bytes` extension from 43 // `std::os::unix::ffi::OsStrExt`). 44 45 let filename = match filename { 46 None => None, 47 Some(raw) => Some(core::str::from_utf8(raw).map_err(drop)?), 48 }; 49 let args = args 50 .map(|raw| core::str::from_utf8(raw).map_err(drop)) 51 .collect::<Result<Vec<_>, _>>()?; 52 53 eprintln!( 54 "GDB tried to run a new process with filename {:?}, and args {:?}", 55 filename, args 56 ); 57 58 self.reset(); 59 60 // when running in single-threaded mode, this PID can be anything 61 Ok(Pid::new(1337).unwrap()) 62 } 63 configure_aslr(&mut self) -> Option<target::ext::extended_mode::ConfigureASLROps<Self>>64 fn configure_aslr(&mut self) -> Option<target::ext::extended_mode::ConfigureASLROps<Self>> { 65 Some(self) 66 } 67 configure_env(&mut self) -> Option<target::ext::extended_mode::ConfigureEnvOps<Self>>68 fn configure_env(&mut self) -> Option<target::ext::extended_mode::ConfigureEnvOps<Self>> { 69 Some(self) 70 } 71 configure_startup_shell( &mut self, ) -> Option<target::ext::extended_mode::ConfigureStartupShellOps<Self>>72 fn configure_startup_shell( 73 &mut self, 74 ) -> Option<target::ext::extended_mode::ConfigureStartupShellOps<Self>> { 75 Some(self) 76 } 77 configure_working_dir( &mut self, ) -> Option<target::ext::extended_mode::ConfigureWorkingDirOps<Self>>78 fn configure_working_dir( 79 &mut self, 80 ) -> Option<target::ext::extended_mode::ConfigureWorkingDirOps<Self>> { 81 Some(self) 82 } 83 } 84 85 impl target::ext::extended_mode::ConfigureASLR for Emu { cfg_aslr(&mut self, enabled: bool) -> TargetResult<(), Self>86 fn cfg_aslr(&mut self, enabled: bool) -> TargetResult<(), Self> { 87 eprintln!("GDB {} ASLR", if enabled { "enabled" } else { "disabled" }); 88 Ok(()) 89 } 90 } 91 92 impl target::ext::extended_mode::ConfigureEnv for Emu { set_env(&mut self, key: &[u8], val: Option<&[u8]>) -> TargetResult<(), Self>93 fn set_env(&mut self, key: &[u8], val: Option<&[u8]>) -> TargetResult<(), Self> { 94 // simplified example: assume UTF-8 key/val env vars 95 let key = core::str::from_utf8(key).map_err(drop)?; 96 let val = match val { 97 None => None, 98 Some(raw) => Some(core::str::from_utf8(raw).map_err(drop)?), 99 }; 100 101 eprintln!("GDB tried to set a new env var: {:?}={:?}", key, val); 102 103 Ok(()) 104 } 105 remove_env(&mut self, key: &[u8]) -> TargetResult<(), Self>106 fn remove_env(&mut self, key: &[u8]) -> TargetResult<(), Self> { 107 let key = core::str::from_utf8(key).map_err(drop)?; 108 eprintln!("GDB tried to set remove a env var: {:?}", key); 109 110 Ok(()) 111 } 112 reset_env(&mut self) -> TargetResult<(), Self>113 fn reset_env(&mut self) -> TargetResult<(), Self> { 114 eprintln!("GDB tried to reset env vars"); 115 116 Ok(()) 117 } 118 } 119 120 impl target::ext::extended_mode::ConfigureStartupShell for Emu { cfg_startup_with_shell(&mut self, enabled: bool) -> TargetResult<(), Self>121 fn cfg_startup_with_shell(&mut self, enabled: bool) -> TargetResult<(), Self> { 122 eprintln!( 123 "GDB {} startup with shell", 124 if enabled { "enabled" } else { "disabled" } 125 ); 126 Ok(()) 127 } 128 } 129 130 impl target::ext::extended_mode::ConfigureWorkingDir for Emu { cfg_working_dir(&mut self, dir: Option<&[u8]>) -> TargetResult<(), Self>131 fn cfg_working_dir(&mut self, dir: Option<&[u8]>) -> TargetResult<(), Self> { 132 let dir = match dir { 133 None => None, 134 Some(raw) => Some(core::str::from_utf8(raw).map_err(drop)?), 135 }; 136 137 match dir { 138 None => eprintln!("GDB reset the working directory"), 139 Some(dir) => eprintln!("GDB set the working directory to {:?}", dir), 140 } 141 142 Ok(()) 143 } 144 } 145