1use crate::{
8 lldb_tid_t, sys, RunMode, SBError, SBEvent, SBFileSpec, SBFrame, SBProcess, SBQueue, SBStream,
9 SBValue, StopReason,
10};
11use std::ffi::{CStr, CString};
12use std::fmt;
13use std::os::raw::c_char;
14use std::ptr;
15
16pub struct SBThread {
61 pub raw: sys::SBThreadRef,
63}
64
65impl SBThread {
66 pub(crate) fn wrap(raw: sys::SBThreadRef) -> SBThread {
68 SBThread { raw }
69 }
70
71 pub(crate) fn maybe_wrap(raw: sys::SBThreadRef) -> Option<SBThread> {
73 if unsafe { sys::SBThreadIsValid(raw) } {
74 Some(SBThread { raw })
75 } else {
76 None
77 }
78 }
79
80 pub fn is_valid(&self) -> bool {
82 unsafe { sys::SBThreadIsValid(self.raw) }
83 }
84
85 #[allow(missing_docs)]
86 pub fn broadcaster_class_name() -> &'static str {
87 unsafe {
88 match CStr::from_ptr(sys::SBThreadGetBroadcasterClassName()).to_str() {
89 Ok(s) => s,
90 _ => panic!("Invalid string?"),
91 }
92 }
93 }
94
95 pub fn stop_reason(&self) -> StopReason {
97 unsafe { sys::SBThreadGetStopReason(self.raw) }
98 }
99
100 pub fn stop_return_value(&self) -> Option<SBValue> {
103 SBValue::maybe_wrap(unsafe { sys::SBThreadGetStopReturnValue(self.raw) })
104 }
105
106 pub fn thread_id(&self) -> lldb_tid_t {
114 unsafe { sys::SBThreadGetThreadID(self.raw) }
115 }
116
117 pub fn index_id(&self) -> u32 {
127 unsafe { sys::SBThreadGetIndexID(self.raw) }
128 }
129
130 pub fn name(&self) -> Option<&str> {
132 unsafe { self.check_null_ptr(sys::SBThreadGetName(self.raw)) }
133 }
134
135 pub fn queue(&self) -> Option<SBQueue> {
142 SBQueue::maybe_wrap(unsafe { sys::SBThreadGetQueue(self.raw) })
143 }
144
145 pub fn queue_name(&self) -> Option<&str> {
150 unsafe { self.check_null_ptr(sys::SBThreadGetQueueName(self.raw)) }
151 }
152
153 pub fn queue_id(&self) -> u64 {
158 unsafe { sys::SBThreadGetQueueID(self.raw) }
159 }
160
161 pub fn suspend(&self) -> Result<(), SBError> {
173 let error: SBError = SBError::default();
174 unsafe { sys::SBThreadSuspend(self.raw, error.raw) };
175 error.into_result()
176 }
177
178 pub fn resume(&self) -> Result<(), SBError> {
182 let error: SBError = SBError::default();
183 unsafe { sys::SBThreadResume(self.raw, error.raw) };
184 error.into_result()
185 }
186
187 pub fn is_suspended(&self) -> bool {
191 unsafe { sys::SBThreadIsSuspended(self.raw) }
192 }
193
194 pub fn is_stopped(&self) -> bool {
196 unsafe { sys::SBThreadIsStopped(self.raw) }
197 }
198
199 pub fn frames(&self) -> SBThreadFrameIter {
203 SBThreadFrameIter {
204 thread: self,
205 idx: 0,
206 }
207 }
208
209 pub fn selected_frame(&self) -> SBFrame {
211 SBFrame::wrap(unsafe { sys::SBThreadGetSelectedFrame(self.raw) })
212 }
213
214 pub fn set_selected_frame(&self, frame_index: u32) -> Option<SBFrame> {
216 SBFrame::maybe_wrap(unsafe { sys::SBThreadSetSelectedFrame(self.raw, frame_index) })
217 }
218
219 pub fn process(&self) -> SBProcess {
221 SBProcess::wrap(unsafe { sys::SBThreadGetProcess(self.raw) })
222 }
223
224 #[allow(missing_docs)]
225 pub fn step_over(&self, stop_other_threads: RunMode) -> Result<(), SBError> {
226 let error = SBError::default();
227 unsafe { sys::SBThreadStepOver(self.raw, stop_other_threads, error.raw) }
228 if error.is_success() {
229 Ok(())
230 } else {
231 Err(error)
232 }
233 }
234
235 #[allow(missing_docs)]
236 pub fn step_into(&self, stop_other_threads: RunMode) {
237 unsafe {
238 sys::SBThreadStepInto(self.raw, stop_other_threads);
239 }
240 }
241
242 #[allow(missing_docs)]
243 pub fn step_into_until(
244 &self,
245 target_name: Option<&str>,
246 end_line: u32,
247 stop_other_threads: RunMode,
248 ) -> Result<(), SBError> {
249 let error = SBError::default();
250 let target_name =
251 target_name.map(|n| CString::new(n).expect("Invalid target_name supplied."));
252 unsafe {
253 sys::SBThreadStepInto3(
254 self.raw,
255 target_name.map(|s| s.as_ptr()).unwrap_or_else(ptr::null),
256 end_line,
257 error.raw,
258 stop_other_threads,
259 );
260 }
261 if error.is_success() {
262 Ok(())
263 } else {
264 Err(error)
265 }
266 }
267
268 #[allow(missing_docs)]
269 pub fn step_out(&self) -> Result<(), SBError> {
270 let error = SBError::default();
271 unsafe { sys::SBThreadStepOut(self.raw, error.raw) }
272 if error.is_success() {
273 Ok(())
274 } else {
275 Err(error)
276 }
277 }
278
279 pub fn step_out_of_frame(&self, frame: &SBFrame) -> Result<(), SBError> {
281 let error = SBError::default();
282 unsafe { sys::SBThreadStepOutOfFrame(self.raw, frame.raw, error.raw) }
283 if error.is_success() {
284 Ok(())
285 } else {
286 Err(error)
287 }
288 }
289
290 #[allow(missing_docs)]
291 pub fn step_instruction(&self, step_over: bool) -> Result<(), SBError> {
292 let error = SBError::default();
293 unsafe { sys::SBThreadStepInstruction(self.raw, step_over, error.raw) }
294 if error.is_success() {
295 Ok(())
296 } else {
297 Err(error)
298 }
299 }
300
301 #[allow(missing_docs)]
302 pub fn step_over_until(
303 &self,
304 frame: &SBFrame,
305 file_spec: &SBFileSpec,
306 line: u32,
307 ) -> Result<(), SBError> {
308 SBError::wrap(unsafe {
309 sys::SBThreadStepOverUntil(self.raw, frame.raw, file_spec.raw, line)
310 })
311 .into_result()
312 }
313
314 pub fn event_as_thread_event(event: &SBEvent) -> Option<SBThreadEvent> {
317 if unsafe { sys::SBThreadEventIsThreadEvent(event.raw) } {
318 Some(SBThreadEvent::new(event))
319 } else {
320 None
321 }
322 }
323
324 unsafe fn check_null_ptr(&self, ptr: *const c_char) -> Option<&str> {
325 if !ptr.is_null() {
326 match CStr::from_ptr(ptr).to_str() {
327 Ok(s) => Some(s),
328 _ => panic!("Invalid string?"),
329 }
330 } else {
331 None
332 }
333 }
334}
335
336pub struct SBThreadFrameIter<'d> {
341 thread: &'d SBThread,
342 idx: usize,
343}
344
345impl Iterator for SBThreadFrameIter<'_> {
346 type Item = SBFrame;
347
348 fn next(&mut self) -> Option<SBFrame> {
349 if self.idx < unsafe { sys::SBThreadGetNumFrames(self.thread.raw) as usize } {
350 let r = Some(SBFrame::wrap(unsafe {
351 sys::SBThreadGetFrameAtIndex(self.thread.raw, self.idx as u32)
352 }));
353 self.idx += 1;
354 r
355 } else {
356 None
357 }
358 }
359
360 fn size_hint(&self) -> (usize, Option<usize>) {
361 let sz = unsafe { sys::SBThreadGetNumFrames(self.thread.raw) } as usize;
362 (sz - self.idx, Some(sz))
363 }
364}
365
366impl ExactSizeIterator for SBThreadFrameIter<'_> {}
367
368impl Clone for SBThread {
369 fn clone(&self) -> SBThread {
370 SBThread {
371 raw: unsafe { sys::CloneSBThread(self.raw) },
372 }
373 }
374}
375
376impl fmt::Debug for SBThread {
377 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
378 let stream = SBStream::new();
379 unsafe { sys::SBThreadGetDescription(self.raw, stream.raw) };
380 write!(fmt, "SBThread {{ {} }}", stream.data())
381 }
382}
383
384impl Drop for SBThread {
385 fn drop(&mut self) {
386 unsafe { sys::DisposeSBThread(self.raw) };
387 }
388}
389
390unsafe impl Send for SBThread {}
391unsafe impl Sync for SBThread {}
392
393pub struct SBThreadEvent<'e> {
395 event: &'e SBEvent,
396}
397
398impl<'e> SBThreadEvent<'e> {
399 pub fn new(event: &'e SBEvent) -> Self {
401 SBThreadEvent { event }
402 }
403
404 pub fn thread(&self) -> SBThread {
406 SBThread::wrap(unsafe { sys::SBThreadGetThreadFromEvent(self.event.raw) })
407 }
408
409 pub fn frame(&self) -> Option<SBFrame> {
411 SBFrame::maybe_wrap(unsafe { sys::SBThreadGetStackFrameFromEvent(self.event.raw) })
412 }
413
414 #[allow(missing_docs)]
415 pub const BROADCAST_BIT_STACK_CHANGED: u32 = (1 << 0);
416 #[allow(missing_docs)]
417 pub const BROADCAST_BIT_THREAD_SUSPENDED: u32 = (1 << 1);
418 #[allow(missing_docs)]
419 pub const BROADCAST_BIT_THREAD_RESUMED: u32 = (1 << 2);
420 #[allow(missing_docs)]
421 pub const BROADCAST_BIT_SELECTED_FRAME_CHANGED: u32 = (1 << 3);
422 #[allow(missing_docs)]
423 pub const BROADCAST_BIT_THREAD_SELECTED: u32 = (1 << 4);
424}
425
426#[cfg(feature = "graphql")]
427#[juniper::graphql_object]
428impl SBThread {
429 fn thread_id(&self) -> i32 {
431 self.thread_id() as i32
432 }
433
434 fn index_id() -> i32 {
436 self.index_id() as i32
437 }
438
439 fn frames() -> Vec<SBFrame> {
440 self.frames().collect()
441 }
442
443 fn selected_frame() -> SBFrame {
444 self.selected_frame()
445 }
446
447 fn process() -> SBProcess {
448 self.process()
449 }
450}