lldb/
target.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::{
8    lldb_addr_t, sys, DescriptionLevel, MatchType, SBAddress, SBAttachInfo, SBBreakpoint,
9    SBBroadcaster, SBDebugger, SBError, SBEvent, SBExpressionOptions, SBFileSpec, SBLaunchInfo,
10    SBModule, SBModuleSpec, SBPlatform, SBProcess, SBStream, SBSymbolContextList, SBValue,
11    SBWatchpoint, SymbolType,
12};
13use lldb_sys::ByteOrder;
14use std::ffi::{CStr, CString};
15use std::fmt;
16
17/// The target program running under the debugger.
18///
19/// # Process Management
20///
21/// Starting a debug session is done by launching the target,
22/// attaching to a running process, or loading a core file.
23///
24/// ## Launching
25///
26/// Launching a process can be done by creating and filling
27/// out an [`SBLaunchInfo`] and calling [`SBTarget::launch()`].
28///
29/// ```no_run
30/// use lldb::*;
31/// fn launch_target(target: &SBTarget) -> Result<SBProcess, SBError> {
32///     let launch_info = SBLaunchInfo::new();
33///     launch_info.set_launch_flags(LaunchFlags::STOP_AT_ENTRY);
34///     // Probably want to set up a listener here.
35///     target.launch(launch_info)
36/// }
37/// ```
38///
39/// ## Attaching
40///
41/// Attaching to a process can be done by creating and filling
42/// out an [`SBAttachInfo`] and calling [`SBTarget::attach()`].
43///
44/// ```no_run
45/// use lldb::{lldb_pid_t, SBAttachInfo, SBError, SBProcess, SBTarget};
46/// fn attach_to_pid(target: &SBTarget, pid: lldb_pid_t) -> Result<SBProcess, SBError> {
47///     let attach_info = SBAttachInfo::new_with_pid(pid);
48///     // Probably want to set up a listener here.
49///     target.attach(attach_info)
50/// }
51/// ```
52///
53/// ## Core Files
54///
55/// ...
56///
57/// # Breakpoints and Watchpoints
58///
59/// ...
60///
61/// # Modules
62///
63/// ...
64///
65/// # Events
66///
67/// ...
68pub struct SBTarget {
69    /// The underlying raw `SBTargetRef`.
70    pub raw: sys::SBTargetRef,
71}
72
73impl SBTarget {
74    /// Construct a new `SBTarget`.
75    pub(crate) fn wrap(raw: sys::SBTargetRef) -> SBTarget {
76        SBTarget { raw }
77    }
78
79    /// Construct a new `Some(SBTarget)` or `None`.
80    pub(crate) fn maybe_wrap(raw: sys::SBTargetRef) -> Option<SBTarget> {
81        if unsafe { sys::SBTargetIsValid(raw) } {
82            Some(SBTarget { raw })
83        } else {
84            None
85        }
86    }
87
88    /// Check whether or not this is a valid `SBTarget` value.
89    pub fn is_valid(&self) -> bool {
90        unsafe { sys::SBTargetIsValid(self.raw) }
91    }
92
93    #[allow(missing_docs)]
94    pub fn broadcaster_class_name() -> &'static str {
95        unsafe {
96            match CStr::from_ptr(sys::SBTargetGetBroadcasterClassName()).to_str() {
97                Ok(s) => s,
98                _ => panic!("Invalid string?"),
99            }
100        }
101    }
102
103    /// Get the [`SBPlatform`] associated with this target.
104    ///
105    /// After return, the platform object should be checked for validity.
106    pub fn platform(&self) -> SBPlatform {
107        unsafe {
108            SBPlatform {
109                raw: sys::SBTargetGetPlatform(self.raw),
110            }
111        }
112    }
113
114    /// Get the [`SBProcess`] associated with this target.
115    pub fn process(&self) -> SBProcess {
116        unsafe {
117            SBProcess {
118                raw: sys::SBTargetGetProcess(self.raw),
119            }
120        }
121    }
122
123    /// Launch a target for debugging.
124    pub fn launch(&self, launch_info: SBLaunchInfo) -> Result<SBProcess, SBError> {
125        let error: SBError = SBError::default();
126        let process =
127            SBProcess::wrap(unsafe { sys::SBTargetLaunch2(self.raw, launch_info.raw, error.raw) });
128        if error.is_success() {
129            Ok(process)
130        } else {
131            Err(error)
132        }
133    }
134
135    #[allow(missing_docs)]
136    pub fn load_core(&self, core_file: &str) -> Result<SBProcess, SBError> {
137        let error: SBError = SBError::default();
138        let core_file = CString::new(core_file).unwrap();
139        let process = SBProcess::wrap(unsafe {
140            sys::SBTargetLoadCore(self.raw, core_file.as_ptr(), error.raw)
141        });
142        if error.is_success() {
143            Ok(process)
144        } else {
145            Err(error)
146        }
147    }
148
149    #[allow(missing_docs)]
150    pub fn attach(&self, attach_info: SBAttachInfo) -> Result<SBProcess, SBError> {
151        let error: SBError = SBError::default();
152        let process =
153            SBProcess::wrap(unsafe { sys::SBTargetAttach(self.raw, attach_info.raw, error.raw) });
154        if error.is_success() {
155            Ok(process)
156        } else {
157            Err(error)
158        }
159    }
160
161    /// Get a filespec for the executable.
162    pub fn executable(&self) -> Option<SBFileSpec> {
163        SBFileSpec::maybe_wrap(unsafe { sys::SBTargetGetExecutable(self.raw) })
164    }
165
166    /// Add a module to the target.
167    pub fn add_module(&self, module: &SBModule) -> bool {
168        unsafe { sys::SBTargetAddModule(self.raw, module.raw) }
169    }
170
171    /// Add a module to the target using an `SBModuleSpec`.
172    pub fn add_module_spec(&self, module_spec: &SBModuleSpec) -> Option<SBModule> {
173        SBModule::maybe_wrap(unsafe { sys::SBTargetAddModuleSpec(self.raw, module_spec.raw) })
174    }
175
176    /// Remove a module from the target.
177    pub fn remove_module(&self, module: &SBModule) -> bool {
178        unsafe { sys::SBTargetRemoveModule(self.raw, module.raw) }
179    }
180
181    /// Get the debugger controlling this target.
182    pub fn debugger(&self) -> SBDebugger {
183        SBDebugger {
184            raw: unsafe { sys::SBTargetGetDebugger(self.raw) },
185        }
186    }
187
188    /// Get an iterator over the [modules] known to this target instance.
189    ///
190    /// [modules]: SBModule
191    pub fn modules(&self) -> SBTargetModuleIter {
192        SBTargetModuleIter {
193            target: self,
194            idx: 0,
195        }
196    }
197
198    /// Find the module for the given `SBFileSpec`.
199    pub fn find_module(&self, file_spec: &SBFileSpec) -> Option<SBModule> {
200        SBModule::maybe_wrap(unsafe { sys::SBTargetFindModule(self.raw, file_spec.raw) })
201    }
202
203    /// Resolve a current file address into a section offset address.
204    pub fn resolve_file_address(&self, file_addr: lldb_addr_t) -> Option<SBAddress> {
205        SBAddress::maybe_wrap(unsafe { sys::SBTargetResolveFileAddress(self.raw, file_addr) })
206    }
207
208    /// Resolve a current load address into a section offset address.
209    ///
210    /// The return value will be `None` if the `vm_addr` doesn't resolve to
211    /// a section within a module.
212    pub fn resolve_load_address(&self, vm_addr: lldb_addr_t) -> Option<SBAddress> {
213        SBAddress::maybe_wrap(unsafe { sys::SBTargetResolveLoadAddress(self.raw, vm_addr) })
214    }
215
216    #[allow(missing_docs)]
217    pub fn delete_breakpoint(&self, break_id: i32) {
218        unsafe { sys::SBTargetBreakpointDelete(self.raw, break_id) };
219    }
220
221    #[allow(missing_docs)]
222    pub fn find_breakpoint_by_id(&self, break_id: i32) -> Option<SBBreakpoint> {
223        SBBreakpoint::maybe_wrap(unsafe { sys::SBTargetFindBreakpointByID(self.raw, break_id) })
224    }
225
226    #[allow(missing_docs)]
227    pub fn enable_all_breakpoints(&self) {
228        unsafe { sys::SBTargetEnableAllBreakpoints(self.raw) };
229    }
230
231    #[allow(missing_docs)]
232    pub fn disable_all_breakpoints(&self) {
233        unsafe { sys::SBTargetDisableAllBreakpoints(self.raw) };
234    }
235
236    #[allow(missing_docs)]
237    pub fn delete_all_breakpoints(&self) {
238        unsafe { sys::SBTargetDeleteAllBreakpoints(self.raw) };
239    }
240
241    #[allow(missing_docs)]
242    pub fn breakpoint_create_by_location(&self, file: &str, line: u32) -> SBBreakpoint {
243        let file = CString::new(file).unwrap();
244        SBBreakpoint::wrap(unsafe {
245            sys::SBTargetBreakpointCreateByLocation(self.raw, file.as_ptr(), line)
246        })
247    }
248
249    #[allow(missing_docs)]
250    pub fn breakpoint_create_by_address(&self, address: lldb_addr_t) -> SBBreakpoint {
251        SBBreakpoint::wrap(unsafe { sys::SBTargetBreakpointCreateByAddress(self.raw, address) })
252    }
253
254    #[allow(missing_docs)]
255    pub fn breakpoint_create_by_sbaddress(&self, address: SBAddress) -> SBBreakpoint {
256        SBBreakpoint::wrap(unsafe {
257            sys::SBTargetBreakpointCreateBySBAddress(self.raw, address.raw)
258        })
259    }
260
261    #[allow(missing_docs)]
262    pub fn breakpoints(&self) -> SBTargetBreakpointIter {
263        SBTargetBreakpointIter {
264            target: self,
265            idx: 0,
266        }
267    }
268
269    #[allow(missing_docs)]
270    pub fn delete_watchpoint(&self, watch_id: i32) {
271        unsafe { sys::SBTargetDeleteWatchpoint(self.raw, watch_id) };
272    }
273
274    #[allow(missing_docs)]
275    pub fn find_watchpoint_by_id(&self, watch_id: i32) -> Option<SBWatchpoint> {
276        SBWatchpoint::maybe_wrap(unsafe { sys::SBTargetFindWatchpointByID(self.raw, watch_id) })
277    }
278
279    #[allow(missing_docs)]
280    pub fn enable_all_watchpoints(&self) {
281        unsafe { sys::SBTargetEnableAllWatchpoints(self.raw) };
282    }
283
284    #[allow(missing_docs)]
285    pub fn disable_all_watchpoints(&self) {
286        unsafe { sys::SBTargetDisableAllWatchpoints(self.raw) };
287    }
288
289    #[allow(missing_docs)]
290    pub fn delete_all_watchpoints(&self) {
291        unsafe { sys::SBTargetDeleteAllWatchpoints(self.raw) };
292    }
293
294    #[allow(missing_docs)]
295    pub fn watch_address(
296        &self,
297        addr: lldb_addr_t,
298        size: usize,
299        read: bool,
300        write: bool,
301    ) -> Result<SBWatchpoint, SBError> {
302        let error: SBError = SBError::default();
303        let watchpoint =
304            unsafe { sys::SBTargetWatchAddress(self.raw, addr, size, read, write, error.raw) };
305        if error.is_success() {
306            Ok(SBWatchpoint::wrap(watchpoint))
307        } else {
308            Err(error)
309        }
310    }
311
312    #[allow(missing_docs)]
313    pub fn watchpoints(&self) -> SBTargetWatchpointIter {
314        SBTargetWatchpointIter {
315            target: self,
316            idx: 0,
317        }
318    }
319
320    #[allow(missing_docs)]
321    pub fn broadcaster(&self) -> SBBroadcaster {
322        SBBroadcaster::wrap(unsafe { sys::SBTargetGetBroadcaster(self.raw) })
323    }
324
325    #[allow(missing_docs)]
326    pub fn find_functions(&self, name: &str, name_type_mask: u32) -> SBSymbolContextList {
327        let name = CString::new(name).unwrap();
328        SBSymbolContextList::wrap(unsafe {
329            sys::SBTargetFindFunctions(self.raw, name.as_ptr(), name_type_mask)
330        })
331    }
332
333    #[allow(missing_docs)]
334    pub fn find_global_functions(
335        &self,
336        name: &str,
337        max_matches: u32,
338        matchtype: MatchType,
339    ) -> SBSymbolContextList {
340        let name = CString::new(name).unwrap();
341        SBSymbolContextList::wrap(unsafe {
342            sys::SBTargetFindGlobalFunctions(self.raw, name.as_ptr(), max_matches, matchtype)
343        })
344    }
345
346    #[allow(missing_docs)]
347    pub fn find_symbols(&self, name: &str, symbol_type: SymbolType) -> SBSymbolContextList {
348        let name = CString::new(name).unwrap();
349        SBSymbolContextList::wrap(unsafe {
350            sys::SBTargetFindSymbols(self.raw, name.as_ptr(), symbol_type)
351        })
352    }
353
354    /// Evaluate an expression.
355    pub fn evaluate_expression(&self, expression: &str, options: &SBExpressionOptions) -> SBValue {
356        let expression = CString::new(expression).unwrap();
357        SBValue::wrap(unsafe {
358            sys::SBTargetEvaluateExpression(self.raw, expression.as_ptr(), options.raw)
359        })
360    }
361
362    #[allow(missing_docs)]
363    pub fn event_as_target_event(event: &SBEvent) -> Option<SBTargetEvent> {
364        if unsafe { sys::SBTargetEventIsTargetEvent(event.raw) } {
365            Some(SBTargetEvent::new(event))
366        } else {
367            None
368        }
369    }
370
371    #[allow(missing_docs)]
372    pub fn get_stack_red_zone_size(&self) -> lldb_addr_t {
373        unsafe { sys::SBTargetGetStackRedZoneSize(self.raw) }
374    }
375
376    #[allow(missing_docs)]
377    pub fn is_loaded(&self, module: &SBModule) -> bool {
378        unsafe { sys::SBTargetIsLoaded(self.raw, module.raw) }
379    }
380
381    #[allow(missing_docs)]
382    pub fn get_launch_info(&self) -> SBLaunchInfo {
383        SBLaunchInfo::wrap(unsafe { sys::SBTargetGetLaunchInfo(self.raw) })
384    }
385
386    #[allow(missing_docs)]
387    pub fn set_launch_info(&self, launch_info: SBLaunchInfo) {
388        unsafe { sys::SBTargetSetLaunchInfo(self.raw, launch_info.raw) };
389    }
390
391    /// Returns the byte order of target
392    pub fn byte_order(&self) -> ByteOrder {
393        unsafe { sys::SBTargetGetByteOrder(self.raw) }
394    }
395
396    /// Returns the size of address in bytes
397    pub fn get_address_byte_size(&self) -> u32 {
398        unsafe { sys::SBTargetGetAddressByteSize(self.raw) }
399    }
400}
401
402impl Clone for SBTarget {
403    fn clone(&self) -> SBTarget {
404        SBTarget {
405            raw: unsafe { sys::CloneSBTarget(self.raw) },
406        }
407    }
408}
409
410impl fmt::Debug for SBTarget {
411    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
412        let stream = SBStream::new();
413        unsafe { sys::SBTargetGetDescription(self.raw, stream.raw, DescriptionLevel::Brief) };
414        write!(fmt, "SBTarget {{ {} }}", stream.data())
415    }
416}
417
418impl Drop for SBTarget {
419    fn drop(&mut self) {
420        unsafe { sys::DisposeSBTarget(self.raw) };
421    }
422}
423
424unsafe impl Send for SBTarget {}
425unsafe impl Sync for SBTarget {}
426
427/// Iterate over the [breakpoints] in a [target].
428///
429/// [breakpoints]: SBBreakpoint
430/// [target]: SBTarget
431pub struct SBTargetBreakpointIter<'d> {
432    target: &'d SBTarget,
433    idx: usize,
434}
435
436impl Iterator for SBTargetBreakpointIter<'_> {
437    type Item = SBBreakpoint;
438
439    fn next(&mut self) -> Option<SBBreakpoint> {
440        if self.idx < unsafe { sys::SBTargetGetNumBreakpoints(self.target.raw) as usize } {
441            let r = Some(SBBreakpoint::wrap(unsafe {
442                sys::SBTargetGetBreakpointAtIndex(self.target.raw, self.idx as u32)
443            }));
444            self.idx += 1;
445            r
446        } else {
447            None
448        }
449    }
450
451    fn size_hint(&self) -> (usize, Option<usize>) {
452        let sz = unsafe { sys::SBTargetGetNumBreakpoints(self.target.raw) } as usize;
453        (sz - self.idx, Some(sz))
454    }
455}
456
457impl ExactSizeIterator for SBTargetBreakpointIter<'_> {}
458
459/// Iterate over the [watchpoints] in a [target].
460///
461/// [watchpoints]: SBWatchpoint
462/// [target]: SBTarget
463pub struct SBTargetWatchpointIter<'d> {
464    target: &'d SBTarget,
465    idx: usize,
466}
467
468impl Iterator for SBTargetWatchpointIter<'_> {
469    type Item = SBWatchpoint;
470
471    fn next(&mut self) -> Option<SBWatchpoint> {
472        if self.idx < unsafe { sys::SBTargetGetNumWatchpoints(self.target.raw) as usize } {
473            let r = Some(SBWatchpoint::wrap(unsafe {
474                sys::SBTargetGetWatchpointAtIndex(self.target.raw, self.idx as u32)
475            }));
476            self.idx += 1;
477            r
478        } else {
479            None
480        }
481    }
482
483    fn size_hint(&self) -> (usize, Option<usize>) {
484        let sz = unsafe { sys::SBTargetGetNumWatchpoints(self.target.raw) } as usize;
485        (sz - self.idx, Some(sz))
486    }
487}
488
489impl ExactSizeIterator for SBTargetWatchpointIter<'_> {}
490
491#[allow(missing_docs)]
492pub struct SBTargetEvent<'e> {
493    event: &'e SBEvent,
494}
495
496#[allow(missing_docs)]
497impl<'e> SBTargetEvent<'e> {
498    pub fn new(event: &'e SBEvent) -> Self {
499        SBTargetEvent { event }
500    }
501
502    pub fn target(&self) -> SBTarget {
503        SBTarget::wrap(unsafe { sys::SBTargetGetTargetFromEvent(self.event.raw) })
504    }
505
506    pub fn modules(&self) -> SBTargetEventModuleIter {
507        SBTargetEventModuleIter {
508            event: self,
509            idx: 0,
510        }
511    }
512}
513
514/// Iterate over the [modules] referenced from a [target event].
515///
516/// [modules]: SBModule
517/// [target event]: SBTargetEvent
518pub struct SBTargetEventModuleIter<'d> {
519    event: &'d SBTargetEvent<'d>,
520    idx: usize,
521}
522
523impl Iterator for SBTargetEventModuleIter<'_> {
524    type Item = SBModule;
525
526    fn next(&mut self) -> Option<SBModule> {
527        if self.idx < unsafe { sys::SBTargetGetNumModulesFromEvent(self.event.event.raw) as usize }
528        {
529            let r = Some(SBModule::wrap(unsafe {
530                sys::SBTargetGetModuleAtIndexFromEvent(self.idx as u32, self.event.event.raw)
531            }));
532            self.idx += 1;
533            r
534        } else {
535            None
536        }
537    }
538
539    fn size_hint(&self) -> (usize, Option<usize>) {
540        let sz = unsafe { sys::SBTargetGetNumModulesFromEvent(self.event.event.raw) } as usize;
541        (sz - self.idx, Some(sz))
542    }
543}
544
545impl ExactSizeIterator for SBTargetEventModuleIter<'_> {}
546
547/// Iterate over the [modules] in a [target].
548///
549/// [modules]: SBModule
550/// [target]: SBTarget
551pub struct SBTargetModuleIter<'d> {
552    target: &'d SBTarget,
553    idx: u32,
554}
555
556impl Iterator for SBTargetModuleIter<'_> {
557    type Item = SBModule;
558
559    fn next(&mut self) -> Option<SBModule> {
560        if self.idx < unsafe { sys::SBTargetGetNumModules(self.target.raw) } {
561            let r = Some(SBModule::wrap(unsafe {
562                sys::SBTargetGetModuleAtIndex(self.target.raw, self.idx)
563            }));
564            self.idx += 1;
565            r
566        } else {
567            None
568        }
569    }
570
571    fn size_hint(&self) -> (usize, Option<usize>) {
572        let sz = unsafe { sys::SBTargetGetNumModules(self.target.raw) } as usize;
573        (sz - self.idx as usize, Some(sz))
574    }
575}
576
577impl ExactSizeIterator for SBTargetModuleIter<'_> {}
578
579#[cfg(feature = "graphql")]
580#[juniper::graphql_object]
581impl SBTarget {
582    fn platform() -> SBPlatform {
583        self.platform()
584    }
585
586    fn process() -> SBProcess {
587        self.process()
588    }
589
590    fn executable() -> Option<SBFileSpec> {
591        self.executable()
592    }
593
594    fn debugger() -> SBDebugger {
595        self.debugger()
596    }
597
598    fn breakpoints() -> Vec<SBBreakpoint> {
599        self.breakpoints().collect()
600    }
601
602    fn watchpoints() -> Vec<SBWatchpoint> {
603        self.watchpoints().collect()
604    }
605}