lldb/
launchinfo.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7use crate::{lldb_pid_t, sys, LaunchFlags, SBFileSpec, SBListener};
8use std::ffi::{CStr, CString};
9use std::os::raw::c_char;
10use std::ptr;
11
12/// Configuration for launching a process.
13///
14/// See [`SBTarget::launch()`].
15///
16/// [`SBTarget::launch()`]: crate::SBTarget::launch()
17#[derive(Debug)]
18pub struct SBLaunchInfo {
19    /// The underlying raw `SBLaunchInfoRef`.
20    pub raw: sys::SBLaunchInfoRef,
21}
22
23impl SBLaunchInfo {
24    /// Construct a new `SBLaunchInfo`.
25    pub fn new() -> SBLaunchInfo {
26        SBLaunchInfo::wrap(unsafe { sys::CreateSBLaunchInfo(ptr::null_mut()) })
27    }
28
29    /// Construct a new `SBLaunchInfo`.
30    pub(crate) fn wrap(raw: sys::SBLaunchInfoRef) -> SBLaunchInfo {
31        SBLaunchInfo { raw }
32    }
33
34    #[allow(missing_docs)]
35    pub fn process_id(&self) -> lldb_pid_t {
36        unsafe { sys::SBLaunchInfoGetProcessID(self.raw) }
37    }
38
39    #[allow(missing_docs)]
40    pub fn user_id(&self) -> Option<u32> {
41        if unsafe { sys::SBLaunchInfoUserIDIsValid(self.raw) } {
42            Some(unsafe { sys::SBLaunchInfoGetUserID(self.raw) })
43        } else {
44            None
45        }
46    }
47
48    #[allow(missing_docs)]
49    pub fn set_user_id(&self, user_id: u32) {
50        unsafe { sys::SBLaunchInfoSetUserID(self.raw, user_id) };
51    }
52
53    #[allow(missing_docs)]
54    pub fn group_id(&self) -> Option<u32> {
55        if unsafe { sys::SBLaunchInfoGroupIDIsValid(self.raw) } {
56            Some(unsafe { sys::SBLaunchInfoGetGroupID(self.raw) })
57        } else {
58            None
59        }
60    }
61
62    #[allow(missing_docs)]
63    pub fn set_group_id(&self, group_id: u32) {
64        unsafe { sys::SBLaunchInfoSetGroupID(self.raw, group_id) };
65    }
66
67    #[allow(missing_docs)]
68    pub fn executable_file(&self) -> Option<SBFileSpec> {
69        SBFileSpec::maybe_wrap(unsafe { sys::SBLaunchInfoGetExecutableFile(self.raw) })
70    }
71
72    /// Set the executable file that will be used to launch the process and
73    /// optionally set it as the first argument in the argument vector.
74    ///
75    /// This only needs to be specified if clients wish to carefully control
76    /// the exact path will be used to launch a binary. If you create a
77    /// target with a symlink, that symlink will get resolved in the target
78    /// and the resolved path will get used to launch the process. Calling
79    /// this function can help you still launch your process using the
80    /// path of your choice.
81    ///
82    /// If this function is not called prior to launching with
83    /// [`SBTarget::launch(...)`], the target will use the resolved executable
84    /// path that was used to create the target.
85    ///
86    /// `exe_file` is the override path to use when launching the executable.
87    ///
88    /// If `add_as_first_arg` is true, then the path will be inserted into
89    /// the argument vector prior to launching. Otherwise the argument
90    /// vector will be left alone.
91    ///
92    /// [`SBTarget::launch(...)`]: crate::SBTarget::launch()
93    pub fn set_executable_file(&self, filespec: &SBFileSpec, add_as_first_arg: bool) {
94        unsafe { sys::SBLaunchInfoSetExecutableFile(self.raw, filespec.raw, add_as_first_arg) };
95    }
96
97    /// Get the listener that will be used to receive process events.
98    ///
99    /// If no listener has been set via a call to
100    /// `SBLaunchInfo::set_listener()`, then `None` will be returned.
101    /// If a listener has been set, then the listener object will be returned.
102    pub fn listener(&self) -> Option<SBListener> {
103        SBListener::maybe_wrap(unsafe { sys::SBLaunchInfoGetListener(self.raw) })
104    }
105
106    /// Set the listener that will be used to receive process events.
107    ///
108    /// By default the [`SBDebugger`], which has a listener,
109    /// that the [`SBTarget`] belongs to will listen for the
110    /// process events. Calling this function allows a different
111    /// listener to be used to listen for process events.
112    ///
113    /// [`SBDebugger`]: crate::SBDebugger
114    /// [`SBTarget`]: crate::SBTarget
115    pub fn set_listener(&self, listener: &SBListener) {
116        unsafe { sys::SBLaunchInfoSetListener(self.raw, listener.raw) };
117    }
118
119    #[allow(missing_docs)]
120    pub fn launch_flags(&self) -> LaunchFlags {
121        LaunchFlags::from_bits_truncate(unsafe { sys::SBLaunchInfoGetLaunchFlags(self.raw) })
122    }
123
124    #[allow(missing_docs)]
125    pub fn set_launch_flags(&self, launch_flags: LaunchFlags) {
126        unsafe { sys::SBLaunchInfoSetLaunchFlags(self.raw, launch_flags.bits()) }
127    }
128
129    /// Specify the command line arguments.
130    pub fn set_arguments<'a>(&self, args: impl IntoIterator<Item = &'a str>, append: bool) {
131        let cstrs: Vec<CString> = args.into_iter().map(|a| CString::new(a).unwrap()).collect();
132        let mut ptrs: Vec<*const c_char> = cstrs.iter().map(|cs| cs.as_ptr()).collect();
133        ptrs.push(ptr::null());
134        let argv = ptrs.as_ptr();
135        unsafe { sys::SBLaunchInfoSetArguments(self.raw, argv, append) };
136    }
137
138    /// Returns an iterator over the command line arguments.
139    pub fn arguments(&self) -> impl Iterator<Item = &str> {
140        SBLaunchInfoArgumentsIter {
141            launch_info: self,
142            index: 0,
143        }
144    }
145
146    #[allow(missing_docs)]
147    fn num_arguments(&self) -> u32 {
148        unsafe { sys::SBLaunchInfoGetNumArguments(self.raw) }
149    }
150
151    #[allow(missing_docs)]
152    fn argument_at_index(&self, index: u32) -> &str {
153        unsafe {
154            match CStr::from_ptr(sys::SBLaunchInfoGetArgumentAtIndex(self.raw, index)).to_str() {
155                Ok(s) => s,
156                _ => panic!("Invalid string?"),
157            }
158        }
159    }
160
161    #[allow(missing_docs)]
162    pub fn process_plugin_name(&self) -> Option<&str> {
163        unsafe {
164            match CStr::from_ptr(sys::SBLaunchInfoGetProcessPluginName(self.raw)).to_str() {
165                Ok(s) => Some(s),
166                _ => None,
167            }
168        }
169    }
170
171    #[allow(missing_docs)]
172    pub fn set_process_plugin_name(&self, plugin: &str) {
173        let plugin = CString::new(plugin).unwrap();
174        unsafe { sys::SBLaunchInfoSetProcessPluginName(self.raw, plugin.as_ptr()) };
175    }
176
177    #[allow(missing_docs)]
178    pub fn shell(&self) -> Option<&str> {
179        unsafe {
180            match CStr::from_ptr(sys::SBLaunchInfoGetShell(self.raw)).to_str() {
181                Ok(s) => Some(s),
182                _ => None,
183            }
184        }
185    }
186
187    #[allow(missing_docs)]
188    pub fn set_shell(&self, shell: &str) {
189        let shell = CString::new(shell).unwrap();
190        unsafe { sys::SBLaunchInfoSetShell(self.raw, shell.as_ptr()) };
191    }
192
193    #[allow(missing_docs)]
194    pub fn shell_expand_arguments(&self) -> bool {
195        unsafe { sys::SBLaunchInfoGetShellExpandArguments(self.raw) }
196    }
197
198    #[allow(missing_docs)]
199    pub fn set_shell_expand_arguments(&self, expand: bool) {
200        unsafe { sys::SBLaunchInfoSetShellExpandArguments(self.raw, expand) };
201    }
202
203    #[allow(missing_docs)]
204    pub fn resume_count(&self) -> u32 {
205        unsafe { sys::SBLaunchInfoGetResumeCount(self.raw) }
206    }
207
208    #[allow(missing_docs)]
209    pub fn set_resume_count(&self, resume_count: u32) {
210        unsafe { sys::SBLaunchInfoSetResumeCount(self.raw, resume_count) };
211    }
212
213    #[allow(missing_docs)]
214    pub fn add_close_file_action(&self, fd: i32) -> bool {
215        unsafe { sys::SBLaunchInfoAddCloseFileAction(self.raw, fd) }
216    }
217
218    #[allow(missing_docs)]
219    pub fn add_duplicate_file_action(&self, fd: i32, dup_fd: i32) -> bool {
220        unsafe { sys::SBLaunchInfoAddDuplicateFileAction(self.raw, fd, dup_fd) }
221    }
222
223    #[allow(missing_docs)]
224    pub fn add_open_file_action(&self, fd: i32, path: &str, read: bool, write: bool) -> bool {
225        let path = CString::new(path).unwrap();
226        unsafe { sys::SBLaunchInfoAddOpenFileAction(self.raw, fd, path.as_ptr(), read, write) }
227    }
228
229    #[allow(missing_docs)]
230    pub fn add_suppress_file_action(&self, fd: i32, read: bool, write: bool) -> bool {
231        unsafe { sys::SBLaunchInfoAddSuppressFileAction(self.raw, fd, read, write) }
232    }
233
234    #[allow(missing_docs)]
235    pub fn launch_event_data(&self) -> Option<&str> {
236        unsafe {
237            match CStr::from_ptr(sys::SBLaunchInfoGetLaunchEventData(self.raw)).to_str() {
238                Ok(s) => Some(s),
239                _ => None,
240            }
241        }
242    }
243
244    #[allow(missing_docs)]
245    pub fn set_launch_event_data(&self, data: &str) {
246        let data = CString::new(data).unwrap();
247        unsafe { sys::SBLaunchInfoSetLaunchEventData(self.raw, data.as_ptr()) };
248    }
249
250    #[allow(missing_docs)]
251    pub fn detach_on_error(&self) -> bool {
252        unsafe { sys::SBLaunchInfoGetDetachOnError(self.raw) }
253    }
254    #[allow(missing_docs)]
255    pub fn set_detach_on_error(&self, detach: bool) {
256        unsafe { sys::SBLaunchInfoSetDetachOnError(self.raw, detach) };
257    }
258}
259
260impl Clone for SBLaunchInfo {
261    fn clone(&self) -> SBLaunchInfo {
262        SBLaunchInfo {
263            raw: unsafe { sys::CloneSBLaunchInfo(self.raw) },
264        }
265    }
266}
267
268impl Default for SBLaunchInfo {
269    fn default() -> SBLaunchInfo {
270        SBLaunchInfo::new()
271    }
272}
273
274impl Drop for SBLaunchInfo {
275    fn drop(&mut self) {
276        unsafe { sys::DisposeSBLaunchInfo(self.raw) };
277    }
278}
279
280unsafe impl Send for SBLaunchInfo {}
281unsafe impl Sync for SBLaunchInfo {}
282
283pub struct SBLaunchInfoArgumentsIter<'d> {
284    launch_info: &'d SBLaunchInfo,
285    index: u32,
286}
287
288impl<'d> Iterator for SBLaunchInfoArgumentsIter<'d> {
289    type Item = &'d str;
290
291    fn next(&mut self) -> Option<&'d str> {
292        if self.index < self.launch_info.num_arguments() {
293            self.index += 1;
294            Some(self.launch_info.argument_at_index(self.index - 1))
295        } else {
296            None
297        }
298    }
299
300    fn size_hint(&self) -> (usize, Option<usize>) {
301        let sz = self.launch_info.num_arguments();
302        (sz as usize - self.index as usize, Some(sz as usize))
303    }
304}
305
306impl ExactSizeIterator for SBLaunchInfoArgumentsIter<'_> {}