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