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