lldb/
value.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, lldb_user_id_t, sys, Format, SBAddress, SBData, SBError, SBFrame, SBProcess,
9    SBStream, SBTarget, SBThread, SBWatchpoint,
10};
11use std::ffi::{CStr, CString};
12use std::fmt;
13use std::os::raw::c_char;
14
15/// The value of a variable, register or expression.
16pub struct SBValue {
17    /// The underlying raw `SBValueRef`.
18    pub raw: sys::SBValueRef,
19}
20
21impl SBValue {
22    /// Construct a new `SBValue`.
23    pub(crate) fn wrap(raw: sys::SBValueRef) -> SBValue {
24        SBValue { raw }
25    }
26
27    /// Construct a new `Some(SBValue)` or `None`.
28    pub(crate) fn maybe_wrap(raw: sys::SBValueRef) -> Option<SBValue> {
29        if unsafe { sys::SBValueIsValid(raw) } {
30            Some(SBValue { raw })
31        } else {
32            None
33        }
34    }
35
36    /// Check whether or not this is a valid `SBValue` value.
37    pub fn is_valid(&self) -> bool {
38        unsafe { sys::SBValueIsValid(self.raw) }
39    }
40
41    #[allow(missing_docs)]
42    pub fn clear(&self) {
43        unsafe { sys::SBValueClear(self.raw) };
44    }
45
46    #[allow(missing_docs)]
47    pub fn error(&self) -> Option<SBError> {
48        SBError::maybe_wrap(unsafe { sys::SBValueGetError(self.raw) })
49    }
50
51    #[allow(missing_docs)]
52    pub fn id(&self) -> lldb_user_id_t {
53        unsafe { sys::SBValueGetID(self.raw) }
54    }
55
56    #[allow(missing_docs)]
57    pub fn name(&self) -> Option<&str> {
58        unsafe { self.check_null_ptr(sys::SBValueGetName(self.raw)) }
59    }
60
61    #[allow(missing_docs)]
62    pub fn type_name(&self) -> Option<&str> {
63        unsafe { self.check_null_ptr(sys::SBValueGetTypeName(self.raw)) }
64    }
65
66    #[allow(missing_docs)]
67    pub fn display_type_name(&self) -> Option<&str> {
68        unsafe { self.check_null_ptr(sys::SBValueGetDisplayTypeName(self.raw)) }
69    }
70
71    #[allow(missing_docs)]
72    pub fn byte_size(&self) -> usize {
73        unsafe { sys::SBValueGetByteSize(self.raw) }
74    }
75
76    #[allow(missing_docs)]
77    pub fn is_in_scope(&self) -> bool {
78        unsafe { sys::SBValueIsInScope(self.raw) }
79    }
80
81    #[allow(missing_docs)]
82    pub fn format(&self) -> Format {
83        unsafe { sys::SBValueGetFormat(self.raw) }
84    }
85
86    #[allow(missing_docs)]
87    pub fn set_format(&self, format: Format) {
88        unsafe { sys::SBValueSetFormat(self.raw, format) }
89    }
90
91    #[allow(missing_docs)]
92    pub fn value(&self) -> Option<&str> {
93        unsafe { self.check_null_ptr(sys::SBValueGetValue(self.raw)) }
94    }
95
96    #[allow(missing_docs)]
97    pub fn set_value_from_cstring(&self, val: &str) -> Result<(), SBError> {
98        let error = SBError::default();
99        let val = CString::new(val).unwrap();
100
101        if unsafe { sys::SBValueSetValueFromCString2(self.raw, val.as_ptr(), error.raw) } {
102            Ok(())
103        } else {
104            Err(error)
105        }
106    }
107
108    #[allow(missing_docs)]
109    pub fn dereference(&self) -> Option<SBValue> {
110        SBValue::maybe_wrap(unsafe { sys::SBValueDereference(self.raw) })
111    }
112
113    #[allow(missing_docs)]
114    pub fn address_of(&self) -> Option<SBValue> {
115        SBValue::maybe_wrap(unsafe { sys::SBValueAddressOf(self.raw) })
116    }
117
118    #[allow(missing_docs)]
119    pub fn type_is_pointer_type(&self) -> bool {
120        unsafe { sys::SBValueTypeIsPointerType(self.raw) }
121    }
122
123    #[allow(missing_docs)]
124    pub fn target(&self) -> SBTarget {
125        SBTarget::wrap(unsafe { sys::SBValueGetTarget(self.raw) })
126    }
127
128    #[allow(missing_docs)]
129    pub fn process(&self) -> SBProcess {
130        SBProcess::wrap(unsafe { sys::SBValueGetProcess(self.raw) })
131    }
132
133    #[allow(missing_docs)]
134    pub fn thread(&self) -> SBThread {
135        SBThread::wrap(unsafe { sys::SBValueGetThread(self.raw) })
136    }
137
138    #[allow(missing_docs)]
139    pub fn frame(&self) -> SBFrame {
140        SBFrame::wrap(unsafe { sys::SBValueGetFrame(self.raw) })
141    }
142
143    /// Get an iterator over the [child values] of this value.
144    ///
145    /// [child values]: SBValue
146    pub fn children(&self) -> SBValueChildIter {
147        SBValueChildIter {
148            value: self,
149            idx: 0,
150        }
151    }
152
153    /// Find and watch a variable.
154    pub fn watch(
155        &self,
156        resolve_location: bool,
157        read: bool,
158        write: bool,
159    ) -> Result<SBWatchpoint, SBError> {
160        let error = SBError::default();
161        let wp = unsafe { sys::SBValueWatch(self.raw, resolve_location, read, write, error.raw) };
162        if error.is_success() {
163            Ok(SBWatchpoint::wrap(wp))
164        } else {
165            Err(error)
166        }
167    }
168
169    /// Find and watch the location pointed to by a variable.
170    pub fn watch_pointee(
171        &self,
172        resolve_location: bool,
173        read: bool,
174        write: bool,
175    ) -> Result<SBWatchpoint, SBError> {
176        let error = SBError::default();
177        let wp =
178            unsafe { sys::SBValueWatchPointee(self.raw, resolve_location, read, write, error.raw) };
179        if error.is_success() {
180            Ok(SBWatchpoint::wrap(wp))
181        } else {
182            Err(error)
183        }
184    }
185
186    /// Get an `SBData` wrapping what this `SBValue` points to.
187    ///
188    /// This method will dereference the current `SBValue`, if its
189    /// data type is a `T*` or `T[]`, and extract `item_count` elements
190    /// of type `T` from it, copying their contents into an `SBData`.
191    ///
192    /// `item_idx` is the index of the first item to retrieve. For an array
193    /// this is equivalent to `array[item_idx]`, for a pointer
194    /// to `*(pointer + item_idx)`. In either case, the measurement
195    /// unit for `item_idx` is the `sizeof(T)` rather than bytes.
196    ///
197    /// `item_count` is how many items should be copied into the output.
198    /// By default only one item is copied, but more can be asked for.
199    ///
200    /// Returns `Some(SBData)` with the contents of the copied items, on success.
201    /// `None` otherwise.
202    pub fn pointee_data(&self, item_idx: u32, item_count: u32) -> Option<SBData> {
203        SBData::maybe_wrap(unsafe { sys::SBValueGetPointeeData(self.raw, item_idx, item_count) })
204    }
205
206    /// Get an `SBData` wrapping the contents of this `SBValue`.
207    ///
208    /// This method will read the contents of this object in memory
209    /// and copy them into an `SBData` for future use.
210    ///
211    /// Returns `Some(SBData)` with the contents of this `SBValue`, on success.
212    /// `None` otherwise.
213    pub fn data(&self) -> Option<SBData> {
214        SBData::maybe_wrap(unsafe { sys::SBValueGetData(self.raw) })
215    }
216
217    #[allow(missing_docs)]
218    pub fn set_data(&self, data: &SBData) -> Result<(), SBError> {
219        let error = SBError::default();
220        if unsafe { sys::SBValueSetData(self.raw, data.raw, error.raw) } {
221            Ok(())
222        } else {
223            Err(error)
224        }
225    }
226
227    #[allow(missing_docs)]
228    pub fn load_address(&self) -> Option<lldb_addr_t> {
229        let load_address = unsafe { sys::SBValueGetLoadAddress(self.raw) };
230        if load_address != u64::MAX {
231            Some(load_address)
232        } else {
233            None
234        }
235    }
236
237    #[allow(missing_docs)]
238    pub fn address(&self) -> Option<SBAddress> {
239        SBAddress::maybe_wrap(unsafe { sys::SBValueGetAddress(self.raw) })
240    }
241
242    unsafe fn check_null_ptr(&self, ptr: *const c_char) -> Option<&str> {
243        if !ptr.is_null() {
244            match CStr::from_ptr(ptr).to_str() {
245                Ok(s) => Some(s),
246                _ => panic!("Invalid string?"),
247            }
248        } else {
249            None
250        }
251    }
252
253    /// Get the value as signed integer
254    pub fn get_as_signed(&self) -> Result<i64, SBError> {
255        let error = SBError::default();
256        let result = unsafe { sys::SBValueGetValueAsSigned(self.raw, error.raw, 0) };
257        if error.is_success() {
258            Ok(result)
259        } else {
260            Err(error)
261        }
262    }
263
264    /// Get the value as unsigned integer
265    pub fn get_as_unsigned(&self) -> Result<u64, SBError> {
266        let error = SBError::default();
267        let result = unsafe { sys::SBValueGetValueAsUnsigned(self.raw, error.raw, 0) };
268        if error.is_success() {
269            Ok(result)
270        } else {
271            Err(error)
272        }
273    }
274}
275
276impl Clone for SBValue {
277    fn clone(&self) -> SBValue {
278        SBValue {
279            raw: unsafe { sys::CloneSBValue(self.raw) },
280        }
281    }
282}
283
284impl fmt::Debug for SBValue {
285    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
286        let stream = SBStream::new();
287        unsafe { sys::SBValueGetDescription(self.raw, stream.raw) };
288        write!(fmt, "SBValue {{ {} }}", stream.data())
289    }
290}
291
292impl Drop for SBValue {
293    fn drop(&mut self) {
294        unsafe { sys::DisposeSBValue(self.raw) };
295    }
296}
297
298unsafe impl Send for SBValue {}
299unsafe impl Sync for SBValue {}
300
301/// Iterate over the child [values] of a [value].
302///
303/// [values]: SBValue
304/// [value]: SBValue
305pub struct SBValueChildIter<'d> {
306    value: &'d SBValue,
307    idx: u32,
308}
309
310impl Iterator for SBValueChildIter<'_> {
311    type Item = SBValue;
312
313    fn next(&mut self) -> Option<SBValue> {
314        if self.idx < unsafe { sys::SBValueGetNumChildren(self.value.raw) } {
315            let r = Some(SBValue::wrap(unsafe {
316                sys::SBValueGetChildAtIndex(self.value.raw, self.idx)
317            }));
318            self.idx += 1;
319            r
320        } else {
321            None
322        }
323    }
324
325    fn size_hint(&self) -> (usize, Option<usize>) {
326        let sz = unsafe { sys::SBValueGetNumChildren(self.value.raw) } as usize;
327        (sz - self.idx as usize, Some(sz))
328    }
329}
330
331impl ExactSizeIterator for SBValueChildIter<'_> {}
332
333#[cfg(feature = "graphql")]
334#[juniper::graphql_object]
335impl SBValue {
336    // TODO(bm): This should be u64
337    fn id() -> i32 {
338        self.id() as i32
339    }
340
341    fn name() -> Option<&str> {
342        self.name()
343    }
344
345    fn type_name() -> Option<&str> {
346        self.type_name()
347    }
348
349    fn display_type_name() -> Option<&str> {
350        self.display_type_name()
351    }
352
353    // TODO(bm): This should be usize.
354    fn byte_size() -> i32 {
355        self.byte_size() as i32
356    }
357
358    fn is_in_scope() -> bool {
359        self.is_in_scope()
360    }
361}