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