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