1 //===-- SBThread.cpp --------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/API/SBThread.h"
11 
12 #include "lldb/API/SBSymbolContext.h"
13 #include "lldb/API/SBFileSpec.h"
14 #include "lldb/API/SBStream.h"
15 #include "lldb/Breakpoint/BreakpointLocation.h"
16 #include "lldb/Core/Debugger.h"
17 #include "lldb/Core/Stream.h"
18 #include "lldb/Core/StreamFile.h"
19 #include "lldb/Interpreter/CommandInterpreter.h"
20 #include "lldb/Target/Thread.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Symbol/SymbolContext.h"
23 #include "lldb/Symbol/CompileUnit.h"
24 #include "lldb/Target/StopInfo.h"
25 #include "lldb/Target/Target.h"
26 #include "lldb/Target/ThreadPlan.h"
27 #include "lldb/Target/ThreadPlanStepInstruction.h"
28 #include "lldb/Target/ThreadPlanStepOut.h"
29 #include "lldb/Target/ThreadPlanStepRange.h"
30 #include "lldb/Target/ThreadPlanStepInRange.h"
31 
32 
33 #include "lldb/API/SBAddress.h"
34 #include "lldb/API/SBFrame.h"
35 #include "lldb/API/SBSourceManager.h"
36 #include "lldb/API/SBDebugger.h"
37 #include "lldb/API/SBProcess.h"
38 
39 using namespace lldb;
40 using namespace lldb_private;
41 
42 //----------------------------------------------------------------------
43 // Constructors
44 //----------------------------------------------------------------------
45 SBThread::SBThread () :
46     m_opaque_sp ()
47 {
48 }
49 
50 SBThread::SBThread (const ThreadSP& lldb_object_sp) :
51     m_opaque_sp (lldb_object_sp)
52 {
53 }
54 
55 SBThread::SBThread (const SBThread &rhs) :
56     m_opaque_sp (rhs.m_opaque_sp)
57 {
58 }
59 
60 //----------------------------------------------------------------------
61 // Assignment operator
62 //----------------------------------------------------------------------
63 
64 const lldb::SBThread &
65 SBThread::operator = (const SBThread &rhs)
66 {
67     if (this != &rhs)
68         m_opaque_sp = rhs.m_opaque_sp;
69     return *this;
70 }
71 
72 //----------------------------------------------------------------------
73 // Destructor
74 //----------------------------------------------------------------------
75 SBThread::~SBThread()
76 {
77 }
78 
79 bool
80 SBThread::IsValid() const
81 {
82     return m_opaque_sp != NULL;
83 }
84 
85 void
86 SBThread::Clear ()
87 {
88     m_opaque_sp.reset();
89 }
90 
91 
92 StopReason
93 SBThread::GetStopReason()
94 {
95     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
96 
97     StopReason reason = eStopReasonInvalid;
98     if (m_opaque_sp)
99     {
100         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
101         StopInfoSP stop_info_sp = m_opaque_sp->GetStopInfo ();
102         if (stop_info_sp)
103             reason =  stop_info_sp->GetStopReason();
104     }
105 
106     if (log)
107         log->Printf ("SBThread(%p)::GetStopReason () => %s", m_opaque_sp.get(),
108                      Thread::StopReasonAsCString (reason));
109 
110     return reason;
111 }
112 
113 size_t
114 SBThread::GetStopReasonDataCount ()
115 {
116     if (m_opaque_sp)
117     {
118         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
119         StopInfoSP stop_info_sp = m_opaque_sp->GetStopInfo ();
120         if (stop_info_sp)
121         {
122             StopReason reason = stop_info_sp->GetStopReason();
123             switch (reason)
124             {
125             case eStopReasonInvalid:
126             case eStopReasonNone:
127             case eStopReasonTrace:
128             case eStopReasonPlanComplete:
129                 // There is no data for these stop reasons.
130                 return 0;
131 
132             case eStopReasonBreakpoint:
133                 {
134                     break_id_t site_id = stop_info_sp->GetValue();
135                     lldb::BreakpointSiteSP bp_site_sp (m_opaque_sp->GetProcess().GetBreakpointSiteList().FindByID (site_id));
136                     if (bp_site_sp)
137                         return bp_site_sp->GetNumberOfOwners () * 2;
138                     else
139                         return 0; // Breakpoint must have cleared itself...
140                 }
141                 break;
142 
143             case eStopReasonWatchpoint:
144                 assert (!"implement watchpoint support in SBThread::GetStopReasonDataCount ()");
145                 return 0; // We don't have watchpoint support yet...
146 
147             case eStopReasonSignal:
148                 return 1;
149 
150             case eStopReasonException:
151                 return 1;
152             }
153         }
154     }
155     return 0;
156 }
157 
158 uint64_t
159 SBThread::GetStopReasonDataAtIndex (uint32_t idx)
160 {
161     if (m_opaque_sp)
162     {
163         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
164         StopInfoSP stop_info_sp = m_opaque_sp->GetStopInfo ();
165         if (stop_info_sp)
166         {
167             StopReason reason = stop_info_sp->GetStopReason();
168             switch (reason)
169             {
170             case eStopReasonInvalid:
171             case eStopReasonNone:
172             case eStopReasonTrace:
173             case eStopReasonPlanComplete:
174                 // There is no data for these stop reasons.
175                 return 0;
176 
177             case eStopReasonBreakpoint:
178                 {
179                     break_id_t site_id = stop_info_sp->GetValue();
180                     lldb::BreakpointSiteSP bp_site_sp (m_opaque_sp->GetProcess().GetBreakpointSiteList().FindByID (site_id));
181                     if (bp_site_sp)
182                     {
183                         uint32_t bp_index = idx / 2;
184                         BreakpointLocationSP bp_loc_sp (bp_site_sp->GetOwnerAtIndex (bp_index));
185                         if (bp_loc_sp)
186                         {
187                             if (bp_index & 1)
188                             {
189                                 // Odd idx, return the breakpoint location ID
190                                 return bp_loc_sp->GetID();
191                             }
192                             else
193                             {
194                                 // Even idx, return the breakpoint ID
195                                 return bp_loc_sp->GetBreakpoint().GetID();
196                             }
197                         }
198                     }
199                     return LLDB_INVALID_BREAK_ID;
200                 }
201                 break;
202 
203             case eStopReasonWatchpoint:
204                 assert (!"implement watchpoint support in SBThread::GetStopReasonDataCount ()");
205                 return 0; // We don't have watchpoint support yet...
206 
207             case eStopReasonSignal:
208                 return stop_info_sp->GetValue();
209 
210             case eStopReasonException:
211                 return stop_info_sp->GetValue();
212             }
213         }
214     }
215     return 0;
216 }
217 
218 size_t
219 SBThread::GetStopDescription (char *dst, size_t dst_len)
220 {
221     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
222 
223     if (m_opaque_sp)
224     {
225         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
226         StopInfoSP stop_info_sp = m_opaque_sp->GetStopInfo ();
227         if (stop_info_sp)
228         {
229             const char *stop_desc = stop_info_sp->GetDescription();
230             if (stop_desc)
231             {
232                 if (log)
233                     log->Printf ("SBThread(%p)::GetStopDescription (dst, dst_len) => \"%s\"",
234                                  m_opaque_sp.get(), stop_desc);
235                 if (dst)
236                     return ::snprintf (dst, dst_len, "%s", stop_desc);
237                 else
238                 {
239                     // NULL dst passed in, return the length needed to contain the description
240                     return ::strlen (stop_desc) + 1; // Include the NULL byte for size
241                 }
242             }
243             else
244             {
245                 size_t stop_desc_len = 0;
246                 switch (stop_info_sp->GetStopReason())
247                 {
248                 case eStopReasonTrace:
249                 case eStopReasonPlanComplete:
250                     {
251                         static char trace_desc[] = "step";
252                         stop_desc = trace_desc;
253                         stop_desc_len = sizeof(trace_desc); // Include the NULL byte for size
254                     }
255                     break;
256 
257                 case eStopReasonBreakpoint:
258                     {
259                         static char bp_desc[] = "breakpoint hit";
260                         stop_desc = bp_desc;
261                         stop_desc_len = sizeof(bp_desc); // Include the NULL byte for size
262                     }
263                     break;
264 
265                 case eStopReasonWatchpoint:
266                     {
267                         static char wp_desc[] = "watchpoint hit";
268                         stop_desc = wp_desc;
269                         stop_desc_len = sizeof(wp_desc); // Include the NULL byte for size
270                     }
271                     break;
272 
273                 case eStopReasonSignal:
274                     {
275                         stop_desc = m_opaque_sp->GetProcess().GetUnixSignals ().GetSignalAsCString (stop_info_sp->GetValue());
276                         if (stop_desc == NULL || stop_desc[0] == '\0')
277                         {
278                             static char signal_desc[] = "signal";
279                             stop_desc = signal_desc;
280                             stop_desc_len = sizeof(signal_desc); // Include the NULL byte for size
281                         }
282                     }
283                     break;
284 
285                 case eStopReasonException:
286                     {
287                         char exc_desc[] = "exception";
288                         stop_desc = exc_desc;
289                         stop_desc_len = sizeof(exc_desc); // Include the NULL byte for size
290                     }
291                     break;
292 
293                 default:
294                     break;
295                 }
296 
297                 if (stop_desc && stop_desc[0])
298                 {
299                     if (log)
300                         log->Printf ("SBThread(%p)::GetStopDescription (dst, dst_len) => '%s'",
301                                      m_opaque_sp.get(), stop_desc);
302 
303                     if (dst)
304                         return ::snprintf (dst, dst_len, "%s", stop_desc) + 1; // Include the NULL byte
305 
306                     if (stop_desc_len == 0)
307                         stop_desc_len = ::strlen (stop_desc) + 1; // Include the NULL byte
308 
309                     return stop_desc_len;
310                 }
311             }
312         }
313     }
314     if (dst)
315         *dst = 0;
316     return 0;
317 }
318 
319 void
320 SBThread::SetThread (const ThreadSP& lldb_object_sp)
321 {
322     m_opaque_sp = lldb_object_sp;
323 }
324 
325 
326 lldb::tid_t
327 SBThread::GetThreadID () const
328 {
329     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
330 
331     lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
332     if (m_opaque_sp)
333         tid = m_opaque_sp->GetID();
334 
335     if (log)
336         log->Printf ("SBThread(%p)::GetThreadID () => 0x%4.4x", m_opaque_sp.get(), tid);
337 
338     return tid;
339 }
340 
341 uint32_t
342 SBThread::GetIndexID () const
343 {
344     if (m_opaque_sp)
345         return m_opaque_sp->GetIndexID();
346     return LLDB_INVALID_INDEX32;
347 }
348 const char *
349 SBThread::GetName () const
350 {
351     const char *name = NULL;
352     if (m_opaque_sp)
353     {
354         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
355         name = m_opaque_sp->GetName();
356     }
357 
358     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
359     if (log)
360         log->Printf ("SBThread(%p)::GetName () => %s", m_opaque_sp.get(), name ? name : "NULL");
361 
362     return name;
363 }
364 
365 const char *
366 SBThread::GetQueueName () const
367 {
368     const char *name = NULL;
369     if (m_opaque_sp)
370     {
371         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
372         name = m_opaque_sp->GetQueueName();
373     }
374 
375     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
376     if (log)
377         log->Printf ("SBThread(%p)::GetQueueName () => %s", m_opaque_sp.get(), name ? name : "NULL");
378 
379     return name;
380 }
381 
382 
383 void
384 SBThread::StepOver (lldb::RunMode stop_other_threads)
385 {
386     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
387 
388     if (log)
389         log->Printf ("SBThread(%p)::StepOver (stop_other_threads='%s')", m_opaque_sp.get(),
390                      Thread::RunModeAsCString (stop_other_threads));
391 
392     if (m_opaque_sp)
393     {
394         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
395         bool abort_other_plans = true;
396         StackFrameSP frame_sp(m_opaque_sp->GetStackFrameAtIndex (0));
397 
398         if (frame_sp)
399         {
400             if (frame_sp->HasDebugInformation ())
401             {
402                 SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
403                 m_opaque_sp->QueueThreadPlanForStepRange (abort_other_plans,
404                                                           eStepTypeOver,
405                                                           sc.line_entry.range,
406                                                           sc,
407                                                           stop_other_threads,
408                                                           false);
409 
410             }
411             else
412             {
413                 m_opaque_sp->QueueThreadPlanForStepSingleInstruction (true,
414                                                                       abort_other_plans,
415                                                                       stop_other_threads);
416             }
417         }
418 
419         Process &process = m_opaque_sp->GetProcess();
420         // Why do we need to set the current thread by ID here???
421         process.GetThreadList().SetSelectedThreadByID (m_opaque_sp->GetID());
422         Error error (process.Resume());
423         if (error.Success())
424         {
425             // If we are doing synchronous mode, then wait for the
426             // process to stop yet again!
427             if (process.GetTarget().GetDebugger().GetAsyncExecution () == false)
428                 process.WaitForProcessToStop (NULL);
429         }
430     }
431 }
432 
433 void
434 SBThread::StepInto (lldb::RunMode stop_other_threads)
435 {
436     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
437 
438     if (log)
439         log->Printf ("SBThread(%p)::StepInto (stop_other_threads='%s')", m_opaque_sp.get(),
440                      Thread::RunModeAsCString (stop_other_threads));
441 
442     if (m_opaque_sp)
443     {
444         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
445         bool abort_other_plans = true;
446 
447         StackFrameSP frame_sp(m_opaque_sp->GetStackFrameAtIndex (0));
448 
449         if (frame_sp && frame_sp->HasDebugInformation ())
450         {
451             bool avoid_code_without_debug_info = true;
452             SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
453             m_opaque_sp->QueueThreadPlanForStepRange (abort_other_plans,
454                                                       eStepTypeInto,
455                                                       sc.line_entry.range,
456                                                       sc,
457                                                       stop_other_threads,
458                                                       avoid_code_without_debug_info);
459         }
460         else
461         {
462             m_opaque_sp->QueueThreadPlanForStepSingleInstruction (false,
463                                                                   abort_other_plans,
464                                                                   stop_other_threads);
465         }
466 
467         Process &process = m_opaque_sp->GetProcess();
468         // Why do we need to set the current thread by ID here???
469         process.GetThreadList().SetSelectedThreadByID (m_opaque_sp->GetID());
470         Error error (process.Resume());
471         if (error.Success())
472         {
473             // If we are doing synchronous mode, then wait for the
474             // process to stop yet again!
475             if (process.GetTarget().GetDebugger().GetAsyncExecution () == false)
476                 process.WaitForProcessToStop (NULL);
477         }
478     }
479 }
480 
481 void
482 SBThread::StepOut ()
483 {
484     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
485 
486     if (log)
487         log->Printf ("SBThread(%p)::StepOut ()", m_opaque_sp.get());
488 
489     if (m_opaque_sp)
490     {
491         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
492         bool abort_other_plans = true;
493         bool stop_other_threads = true;
494 
495         m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, stop_other_threads, eVoteYes, eVoteNoOpinion);
496 
497         Process &process = m_opaque_sp->GetProcess();
498         process.GetThreadList().SetSelectedThreadByID (m_opaque_sp->GetID());
499         Error error (process.Resume());
500         if (error.Success())
501         {
502             // If we are doing synchronous mode, then wait for the
503             // process to stop yet again!
504             if (process.GetTarget().GetDebugger().GetAsyncExecution () == false)
505                 process.WaitForProcessToStop (NULL);
506         }
507     }
508 }
509 
510 void
511 SBThread::StepInstruction (bool step_over)
512 {
513     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
514 
515     if (log)
516         log->Printf ("SBThread(%p)::StepInstruction (step_over=%i)", m_opaque_sp.get(), step_over);
517 
518     if (m_opaque_sp)
519     {
520         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
521         m_opaque_sp->QueueThreadPlanForStepSingleInstruction (step_over, true, true);
522         Process &process = m_opaque_sp->GetProcess();
523         process.GetThreadList().SetSelectedThreadByID (m_opaque_sp->GetID());
524         Error error (process.Resume());
525         if (error.Success())
526         {
527             // If we are doing synchronous mode, then wait for the
528             // process to stop yet again!
529             if (process.GetTarget().GetDebugger().GetAsyncExecution () == false)
530                 process.WaitForProcessToStop (NULL);
531         }
532     }
533 }
534 
535 void
536 SBThread::RunToAddress (lldb::addr_t addr)
537 {
538     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
539 
540     if (log)
541         log->Printf ("SBThread(%p)::RunToAddress (addr=0x%llx)", m_opaque_sp.get(), addr);
542 
543     if (m_opaque_sp)
544     {
545         bool abort_other_plans = true;
546         bool stop_other_threads = true;
547 
548         Address target_addr (NULL, addr);
549 
550         m_opaque_sp->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads);
551         Process &process = m_opaque_sp->GetProcess();
552         process.GetThreadList().SetSelectedThreadByID (m_opaque_sp->GetID());
553         Error error (process.Resume());
554         if (error.Success())
555         {
556             // If we are doing synchronous mode, then wait for the
557             // process to stop yet again!
558             if (process.GetTarget().GetDebugger().GetAsyncExecution () == false)
559                 process.WaitForProcessToStop (NULL);
560         }
561     }
562 
563 }
564 
565 SBProcess
566 SBThread::GetProcess ()
567 {
568 
569     SBProcess process;
570     if (m_opaque_sp)
571     {
572         // Have to go up to the target so we can get a shared pointer to our process...
573         process.SetProcess(m_opaque_sp->GetProcess().GetTarget().GetProcessSP());
574     }
575 
576     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
577     if (log)
578     {
579         SBStream sstr;
580         process.GetDescription (sstr);
581         log->Printf ("SBThread(%p)::GetProcess () => SBProcess(%p): %s", m_opaque_sp.get(),
582                      process.get(), sstr.GetData());
583     }
584 
585     return process;
586 }
587 
588 uint32_t
589 SBThread::GetNumFrames ()
590 {
591     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
592 
593     uint32_t num_frames = 0;
594     if (m_opaque_sp)
595     {
596         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
597         num_frames = m_opaque_sp->GetStackFrameCount();
598     }
599 
600     if (log)
601         log->Printf ("SBThread(%p)::GetNumFrames () => %u", m_opaque_sp.get(), num_frames);
602 
603     return num_frames;
604 }
605 
606 SBFrame
607 SBThread::GetFrameAtIndex (uint32_t idx)
608 {
609     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
610 
611     SBFrame sb_frame;
612     if (m_opaque_sp)
613     {
614         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
615         sb_frame.SetFrame (m_opaque_sp->GetStackFrameAtIndex (idx));
616     }
617 
618     if (log)
619     {
620         SBStream sstr;
621         sb_frame.GetDescription (sstr);
622         log->Printf ("SBThread(%p)::GetFrameAtIndex (idx=%d) => SBFrame(%p): %s",
623                      m_opaque_sp.get(), idx, sb_frame.get(), sstr.GetData());
624     }
625 
626     return sb_frame;
627 }
628 
629 lldb::SBFrame
630 SBThread::GetSelectedFrame ()
631 {
632     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
633 
634     SBFrame sb_frame;
635     if (m_opaque_sp)
636     {
637         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
638         sb_frame.SetFrame (m_opaque_sp->GetSelectedFrame ());
639     }
640 
641     if (log)
642     {
643         SBStream sstr;
644         sb_frame.GetDescription (sstr);
645         log->Printf ("SBThread(%p)::GetSelectedFrame () => SBFrame(%p): %s",
646                      m_opaque_sp.get(), sb_frame.get(), sstr.GetData());
647     }
648 
649     return sb_frame;
650 }
651 
652 lldb::SBFrame
653 SBThread::SetSelectedFrame (uint32_t idx)
654 {
655     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
656 
657     SBFrame sb_frame;
658     if (m_opaque_sp)
659     {
660         Mutex::Locker api_locker (m_opaque_sp->GetProcess().GetTarget().GetAPIMutex());
661         lldb::StackFrameSP frame_sp (m_opaque_sp->GetStackFrameAtIndex (idx));
662         if (frame_sp)
663         {
664             m_opaque_sp->SetSelectedFrame (frame_sp.get());
665             sb_frame.SetFrame (frame_sp);
666         }
667     }
668 
669     if (log)
670     {
671         SBStream sstr;
672         sb_frame.GetDescription (sstr);
673         log->Printf ("SBThread(%p)::SetSelectedFrame (idx=%u) => SBFrame(%p): %s",
674                      m_opaque_sp.get(), idx, sb_frame.get(), sstr.GetData());
675     }
676     return sb_frame;
677 }
678 
679 
680 bool
681 SBThread::operator == (const SBThread &rhs) const
682 {
683     return m_opaque_sp.get() == rhs.m_opaque_sp.get();
684 }
685 
686 bool
687 SBThread::operator != (const SBThread &rhs) const
688 {
689     return m_opaque_sp.get() != rhs.m_opaque_sp.get();
690 }
691 
692 lldb_private::Thread *
693 SBThread::get ()
694 {
695     return m_opaque_sp.get();
696 }
697 
698 const lldb_private::Thread *
699 SBThread::operator->() const
700 {
701     return m_opaque_sp.get();
702 }
703 
704 const lldb_private::Thread &
705 SBThread::operator*() const
706 {
707     return *m_opaque_sp;
708 }
709 
710 lldb_private::Thread *
711 SBThread::operator->()
712 {
713     return m_opaque_sp.get();
714 }
715 
716 lldb_private::Thread &
717 SBThread::operator*()
718 {
719     return *m_opaque_sp;
720 }
721 
722 bool
723 SBThread::GetDescription (SBStream &description) const
724 {
725     if (m_opaque_sp)
726     {
727         StreamString strm;
728         description.Printf("SBThread: tid = 0x%4.4x", m_opaque_sp->GetID());
729     }
730     else
731         description.Printf ("No value");
732 
733     return true;
734 }
735