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/Core/Debugger.h"
15 #include "lldb/Core/Stream.h"
16 #include "lldb/Core/StreamFile.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Target/Thread.h"
19 #include "lldb/Target/Process.h"
20 #include "lldb/Symbol/SymbolContext.h"
21 #include "lldb/Symbol/CompileUnit.h"
22 #include "lldb/Target/Target.h"
23 #include "lldb/Target/ThreadPlan.h"
24 #include "lldb/Target/ThreadPlanStepInstruction.h"
25 #include "lldb/Target/ThreadPlanStepOut.h"
26 #include "lldb/Target/ThreadPlanStepRange.h"
27 #include "lldb/Target/ThreadPlanStepInRange.h"
28 
29 
30 #include "lldb/API/SBAddress.h"
31 #include "lldb/API/SBFrame.h"
32 #include "lldb/API/SBSourceManager.h"
33 #include "lldb/API/SBDebugger.h"
34 #include "lldb/API/SBProcess.h"
35 
36 using namespace lldb;
37 using namespace lldb_private;
38 
39 SBThread::SBThread () :
40     m_opaque_sp ()
41 {
42 }
43 
44 //----------------------------------------------------------------------
45 // Thread constructor
46 //----------------------------------------------------------------------
47 SBThread::SBThread (const ThreadSP& lldb_object_sp) :
48     m_opaque_sp (lldb_object_sp)
49 {
50 }
51 
52 SBThread::SBThread (const SBThread &rhs)
53 {
54     m_opaque_sp = rhs.m_opaque_sp;
55 }
56 
57 //----------------------------------------------------------------------
58 // Destructor
59 //----------------------------------------------------------------------
60 SBThread::~SBThread()
61 {
62 }
63 
64 bool
65 SBThread::IsValid() const
66 {
67     return m_opaque_sp != NULL;
68 }
69 
70 StopReason
71 SBThread::GetStopReason()
72 {
73     if (m_opaque_sp)
74     {
75         lldb_private::Thread::StopInfo thread_stop_info;
76         if (m_opaque_sp->GetStopInfo(&thread_stop_info))
77             return thread_stop_info.GetStopReason();
78     }
79     return eStopReasonInvalid;
80 }
81 
82 size_t
83 SBThread::GetStopDescription (char *dst, size_t dst_len)
84 {
85     if (m_opaque_sp)
86     {
87         lldb_private::Thread::StopInfo thread_stop_info;
88         if (m_opaque_sp->GetStopInfo(&thread_stop_info))
89         {
90             const char *stop_desc = thread_stop_info.GetStopDescription();
91             if (stop_desc)
92             {
93                 if (dst)
94                     return ::snprintf (dst, dst_len, "%s", stop_desc);
95                 else
96                 {
97                     // NULL dst passed in, return the length needed to contain the description
98                     return ::strlen (stop_desc) + 1; // Include the NULL byte for size
99                 }
100             }
101             else
102             {
103                 const char *stop_desc = NULL;
104                 size_t stop_desc_len = 0;
105                 switch (thread_stop_info.GetStopReason())
106                 {
107                 case eStopReasonTrace:
108                 case eStopReasonPlanComplete:
109                     {
110                         static char trace_desc[] = "step";
111                         stop_desc = trace_desc;
112                         stop_desc_len = sizeof(trace_desc); // Include the NULL byte for size
113                     }
114                     break;
115 
116                 case eStopReasonBreakpoint:
117                     {
118                         static char bp_desc[] = "breakpoint hit";
119                         stop_desc = bp_desc;
120                         stop_desc_len = sizeof(bp_desc); // Include the NULL byte for size
121                     }
122                     break;
123 
124                 case eStopReasonWatchpoint:
125                     {
126                         static char wp_desc[] = "watchpoint hit";
127                         stop_desc = wp_desc;
128                         stop_desc_len = sizeof(wp_desc); // Include the NULL byte for size
129                     }
130                     break;
131 
132                 case eStopReasonSignal:
133                     {
134                         stop_desc = m_opaque_sp->GetProcess().GetUnixSignals ().GetSignalAsCString (thread_stop_info.GetSignal());
135                         if (stop_desc == NULL || stop_desc[0] == '\0')
136                         {
137                             static char signal_desc[] = "signal";
138                             stop_desc = signal_desc;
139                             stop_desc_len = sizeof(signal_desc); // Include the NULL byte for size
140                         }
141                     }
142                     break;
143 
144                 case eStopReasonException:
145                     {
146                         char exc_desc[] = "exception";
147                         stop_desc = exc_desc;
148                         stop_desc_len = sizeof(exc_desc); // Include the NULL byte for size
149                     }
150                     break;
151 
152                 default:
153                     break;
154                 }
155 
156                 if (stop_desc && stop_desc[0])
157                 {
158                     if (dst)
159                         return ::snprintf (dst, dst_len, "%s", stop_desc) + 1; // Include the NULL byte
160 
161                     if (stop_desc_len == 0)
162                         stop_desc_len = ::strlen (stop_desc) + 1; // Include the NULL byte
163 
164                     return stop_desc_len;
165                 }
166             }
167         }
168     }
169     if (dst)
170         *dst = 0;
171     return 0;
172 }
173 
174 void
175 SBThread::SetThread (const ThreadSP& lldb_object_sp)
176 {
177     m_opaque_sp = lldb_object_sp;
178 }
179 
180 
181 lldb::tid_t
182 SBThread::GetThreadID () const
183 {
184     if (m_opaque_sp)
185         return m_opaque_sp->GetID();
186     else
187         return LLDB_INVALID_THREAD_ID;
188 }
189 
190 uint32_t
191 SBThread::GetIndexID () const
192 {
193     if (m_opaque_sp)
194         return m_opaque_sp->GetIndexID();
195     return LLDB_INVALID_INDEX32;
196 }
197 const char *
198 SBThread::GetName () const
199 {
200     if (m_opaque_sp)
201         return m_opaque_sp->GetName();
202     return NULL;
203 }
204 
205 const char *
206 SBThread::GetQueueName () const
207 {
208     if (m_opaque_sp)
209         return m_opaque_sp->GetQueueName();
210     return NULL;
211 }
212 
213 
214 void
215 SBThread::DisplayFramesForCurrentContext (FILE *out,
216                                           FILE *err,
217                                           uint32_t first_frame,
218                                           uint32_t num_frames,
219                                           bool show_frame_info,
220                                           uint32_t num_frames_with_source,
221                                           uint32_t source_lines_before,
222                                           uint32_t source_lines_after)
223 {
224     if ((out == NULL) || (err == NULL))
225         return;
226 
227     if (m_opaque_sp)
228     {
229         uint32_t num_stack_frames = m_opaque_sp->GetStackFrameCount ();
230         StackFrameSP frame_sp;
231         uint32_t frame_idx = 0;
232 
233         for (frame_idx = first_frame; frame_idx < first_frame + num_frames; ++frame_idx)
234         {
235             if (frame_idx >= num_stack_frames)
236                 break;
237 
238             frame_sp = m_opaque_sp->GetStackFrameAtIndex (frame_idx);
239             if (!frame_sp)
240                 break;
241 
242             SBFrame sb_frame (frame_sp);
243             if (DisplaySingleFrameForCurrentContext (out,
244                                                      err,
245                                                      sb_frame,
246                                                      show_frame_info,
247                                                      num_frames_with_source > first_frame - frame_idx,
248                                                      source_lines_before,
249                                                      source_lines_after) == false)
250                 break;
251         }
252     }
253 }
254 
255 bool
256 SBThread::DisplaySingleFrameForCurrentContext (FILE *out,
257                                                FILE *err,
258                                                SBFrame &frame,
259                                                bool show_frame_info,
260                                                bool show_source,
261                                                uint32_t source_lines_after,
262                                                uint32_t source_lines_before)
263 {
264     bool success = false;
265 
266     if ((out == NULL) || (err == NULL))
267         return false;
268 
269     if (m_opaque_sp && frame.IsValid())
270     {
271         StreamFile str (out);
272 
273         SBSymbolContext sc(frame.GetSymbolContext(eSymbolContextEverything));
274 
275         if (show_frame_info && sc.IsValid())
276         {
277             user_id_t frame_idx = (user_id_t) frame.GetFrameID();
278             lldb::addr_t pc = frame.GetPC();
279             ::fprintf (out,
280                        "     frame #%u: tid = 0x%4.4x, pc = 0x%llx ",
281                        frame_idx,
282                        GetThreadID(),
283                        pc);
284             sc->DumpStopContext (&str, &m_opaque_sp->GetProcess(), *frame.GetPCAddress());
285             fprintf (out, "\n");
286             success = true;
287         }
288 
289         SBCompileUnit comp_unit(sc.GetCompileUnit());
290         if (show_source && comp_unit.IsValid())
291         {
292             success = false;
293             SBLineEntry line_entry;
294             if (line_entry.IsValid())
295             {
296                 SourceManager& source_manager = m_opaque_sp->GetProcess().GetTarget().GetDebugger().GetSourceManager();
297                 SBFileSpec line_entry_file_spec (line_entry.GetFileSpec());
298 
299                 if (line_entry_file_spec.IsValid())
300                 {
301                     source_manager.DisplaySourceLinesWithLineNumbers (line_entry_file_spec.ref(),
302                                                                       line_entry.GetLine(),
303                                                                       source_lines_after,
304                                                                       source_lines_before, "->",
305                                                                       &str);
306                     success = true;
307                 }
308             }
309         }
310     }
311     return success;
312 }
313 
314 void
315 SBThread::StepOver (lldb::RunMode stop_other_threads)
316 {
317     if (m_opaque_sp)
318     {
319         bool abort_other_plans = true;
320         StackFrameSP frame_sp(m_opaque_sp->GetStackFrameAtIndex (0));
321 
322         if (frame_sp)
323         {
324             if (frame_sp->HasDebugInformation ())
325             {
326                 SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
327                 m_opaque_sp->QueueThreadPlanForStepRange (abort_other_plans,
328                                                                eStepTypeOver,
329                                                                sc.line_entry.range,
330                                                                sc,
331                                                                stop_other_threads,
332                                                                false);
333 
334             }
335             else
336             {
337                 m_opaque_sp->QueueThreadPlanForStepSingleInstruction (true,
338                                                                            abort_other_plans,
339                                                                            stop_other_threads);
340             }
341         }
342 
343         Process &process = m_opaque_sp->GetProcess();
344         // Why do we need to set the current thread by ID here???
345         process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID());
346         process.Resume();
347     }
348 }
349 
350 void
351 SBThread::StepInto (lldb::RunMode stop_other_threads)
352 {
353     if (m_opaque_sp)
354     {
355         bool abort_other_plans = true;
356 
357         StackFrameSP frame_sp(m_opaque_sp->GetStackFrameAtIndex (0));
358 
359         if (frame_sp && frame_sp->HasDebugInformation ())
360         {
361             bool avoid_code_without_debug_info = true;
362             SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
363             m_opaque_sp->QueueThreadPlanForStepRange (abort_other_plans,
364                                                            eStepTypeInto,
365                                                            sc.line_entry.range,
366                                                            sc,
367                                                            stop_other_threads,
368                                                            avoid_code_without_debug_info);
369         }
370         else
371         {
372             m_opaque_sp->QueueThreadPlanForStepSingleInstruction (false,
373                                                                        abort_other_plans,
374                                                                        stop_other_threads);
375         }
376 
377         Process &process = m_opaque_sp->GetProcess();
378         // Why do we need to set the current thread by ID here???
379         process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID());
380         process.Resume();
381 
382     }
383 }
384 
385 void
386 SBThread::StepOut ()
387 {
388     if (m_opaque_sp)
389     {
390         bool abort_other_plans = true;
391         bool stop_other_threads = true;
392 
393         m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, stop_other_threads, eVoteYes, eVoteNoOpinion);
394 
395         Process &process = m_opaque_sp->GetProcess();
396         process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID());
397         process.Resume();
398     }
399 }
400 
401 void
402 SBThread::StepInstruction (bool step_over)
403 {
404     if (m_opaque_sp)
405     {
406         m_opaque_sp->QueueThreadPlanForStepSingleInstruction (step_over, true, true);
407         Process &process = m_opaque_sp->GetProcess();
408         process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID());
409         process.Resume();
410     }
411 }
412 
413 void
414 SBThread::RunToAddress (lldb::addr_t addr)
415 {
416     if (m_opaque_sp)
417     {
418         bool abort_other_plans = true;
419         bool stop_other_threads = true;
420 
421         Address target_addr (NULL, addr);
422 
423         m_opaque_sp->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads);
424         Process &process = m_opaque_sp->GetProcess();
425         process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID());
426         process.Resume();
427     }
428 
429 }
430 
431 SBProcess
432 SBThread::GetProcess ()
433 {
434     SBProcess process;
435     if (m_opaque_sp)
436     {
437         // Have to go up to the target so we can get a shared pointer to our process...
438         process.SetProcess(m_opaque_sp->GetProcess().GetTarget().GetProcessSP());
439     }
440     return process;
441 }
442 
443 uint32_t
444 SBThread::GetNumFrames ()
445 {
446     if (m_opaque_sp)
447         return m_opaque_sp->GetStackFrameCount();
448     return 0;
449 }
450 
451 SBFrame
452 SBThread::GetFrameAtIndex (uint32_t idx)
453 {
454     SBFrame sb_frame;
455     if (m_opaque_sp)
456         sb_frame.SetFrame (m_opaque_sp->GetStackFrameAtIndex (idx));
457     return sb_frame;
458 }
459 
460 const lldb::SBThread &
461 SBThread::operator = (const lldb::SBThread &rhs)
462 {
463     m_opaque_sp = rhs.m_opaque_sp;
464     return *this;
465 }
466 
467 bool
468 SBThread::operator == (const SBThread &rhs) const
469 {
470     return m_opaque_sp.get() == rhs.m_opaque_sp.get();
471 }
472 
473 bool
474 SBThread::operator != (const SBThread &rhs) const
475 {
476     return m_opaque_sp.get() != rhs.m_opaque_sp.get();
477 }
478 
479 lldb_private::Thread *
480 SBThread::GetLLDBObjectPtr ()
481 {
482     return m_opaque_sp.get();
483 }
484 
485 const lldb_private::Thread *
486 SBThread::operator->() const
487 {
488     return m_opaque_sp.get();
489 }
490 
491 const lldb_private::Thread &
492 SBThread::operator*() const
493 {
494     return *m_opaque_sp;
495 }
496 
497 lldb_private::Thread *
498 SBThread::operator->()
499 {
500     return m_opaque_sp.get();
501 }
502 
503 lldb_private::Thread &
504 SBThread::operator*()
505 {
506     return *m_opaque_sp;
507 }
508