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