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                 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_opaque_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                 default:
152                     break;
153                 }
154 
155                 if (stop_desc && stop_desc[0])
156                 {
157                     if (dst)
158                         return ::snprintf (dst, dst_len, "%s", stop_desc) + 1; // Include the NULL byte
159 
160                     if (stop_desc_len == 0)
161                         stop_desc_len = ::strlen (stop_desc) + 1; // Include the NULL byte
162 
163                     return stop_desc_len;
164                 }
165             }
166         }
167     }
168     if (dst)
169         *dst = 0;
170     return 0;
171 }
172 
173 void
174 SBThread::SetThread (const ThreadSP& lldb_object_sp)
175 {
176     m_opaque_sp = lldb_object_sp;
177 }
178 
179 
180 lldb::tid_t
181 SBThread::GetThreadID () const
182 {
183     if (m_opaque_sp)
184         return m_opaque_sp->GetID();
185     else
186         return LLDB_INVALID_THREAD_ID;
187 }
188 
189 uint32_t
190 SBThread::GetIndexID () const
191 {
192     if (m_opaque_sp)
193         return m_opaque_sp->GetIndexID();
194     return LLDB_INVALID_INDEX32;
195 }
196 const char *
197 SBThread::GetName () const
198 {
199     if (m_opaque_sp)
200         return m_opaque_sp->GetName();
201     return NULL;
202 }
203 
204 const char *
205 SBThread::GetQueueName () const
206 {
207     if (m_opaque_sp)
208         return m_opaque_sp->GetQueueName();
209     return NULL;
210 }
211 
212 
213 void
214 SBThread::DisplayFramesForCurrentContext (FILE *out,
215                                           FILE *err,
216                                           uint32_t first_frame,
217                                           uint32_t num_frames,
218                                           bool show_frame_info,
219                                           uint32_t num_frames_with_source,
220                                           uint32_t source_lines_before,
221                                           uint32_t source_lines_after)
222 {
223     if ((out == NULL) || (err == NULL))
224         return;
225 
226     if (m_opaque_sp)
227     {
228         uint32_t num_stack_frames = m_opaque_sp->GetStackFrameCount ();
229         StackFrameSP frame_sp;
230         uint32_t frame_idx = 0;
231 
232         for (frame_idx = first_frame; frame_idx < first_frame + num_frames; ++frame_idx)
233         {
234             if (frame_idx >= num_stack_frames)
235                 break;
236 
237             frame_sp = m_opaque_sp->GetStackFrameAtIndex (frame_idx);
238             if (!frame_sp)
239                 break;
240 
241             SBFrame sb_frame (frame_sp);
242             if (DisplaySingleFrameForCurrentContext (out,
243                                                      err,
244                                                      sb_frame,
245                                                      show_frame_info,
246                                                      num_frames_with_source > first_frame - frame_idx,
247                                                      source_lines_before,
248                                                      source_lines_after) == false)
249                 break;
250         }
251     }
252 }
253 
254 bool
255 SBThread::DisplaySingleFrameForCurrentContext (FILE *out,
256                                                FILE *err,
257                                                SBFrame &frame,
258                                                bool show_frame_info,
259                                                bool show_source,
260                                                uint32_t source_lines_after,
261                                                uint32_t source_lines_before)
262 {
263     bool success = false;
264 
265     if ((out == NULL) || (err == NULL))
266         return false;
267 
268     if (m_opaque_sp && frame.IsValid())
269     {
270         StreamFile str (out);
271 
272         SBSymbolContext sc(frame.GetSymbolContext(eSymbolContextEverything));
273 
274         if (show_frame_info && sc.IsValid())
275         {
276             user_id_t frame_idx = (user_id_t) frame.GetFrameID();
277             lldb::addr_t pc = frame.GetPC();
278             ::fprintf (out,
279                        "     frame #%u: tid = 0x%4.4x, pc = 0x%llx ",
280                        frame_idx,
281                        GetThreadID(),
282                        (long long)pc);
283             sc->DumpStopContext (&str, &m_opaque_sp->GetProcess(), *frame.GetPCAddress());
284             fprintf (out, "\n");
285             success = true;
286         }
287 
288         SBCompileUnit comp_unit(sc.GetCompileUnit());
289         if (show_source && comp_unit.IsValid())
290         {
291             success = false;
292             SBLineEntry line_entry;
293             if (line_entry.IsValid())
294             {
295                 SourceManager& source_manager = m_opaque_sp->GetProcess().GetTarget().GetDebugger().GetSourceManager();
296                 SBFileSpec line_entry_file_spec (line_entry.GetFileSpec());
297 
298                 if (line_entry_file_spec.IsValid())
299                 {
300                     source_manager.DisplaySourceLinesWithLineNumbers (line_entry_file_spec.ref(),
301                                                                       line_entry.GetLine(),
302                                                                       source_lines_after,
303                                                                       source_lines_before, "->",
304                                                                       &str);
305                     success = true;
306                 }
307             }
308         }
309     }
310     return success;
311 }
312 
313 void
314 SBThread::StepOver (lldb::RunMode stop_other_threads)
315 {
316     if (m_opaque_sp)
317     {
318         bool abort_other_plans = true;
319         StackFrameSP frame_sp(m_opaque_sp->GetStackFrameAtIndex (0));
320 
321         if (frame_sp)
322         {
323             if (frame_sp->HasDebugInformation ())
324             {
325                 SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
326                 m_opaque_sp->QueueThreadPlanForStepRange (abort_other_plans,
327                                                                eStepTypeOver,
328                                                                sc.line_entry.range,
329                                                                sc,
330                                                                stop_other_threads,
331                                                                false);
332 
333             }
334             else
335             {
336                 m_opaque_sp->QueueThreadPlanForStepSingleInstruction (true,
337                                                                            abort_other_plans,
338                                                                            stop_other_threads);
339             }
340         }
341 
342         Process &process = m_opaque_sp->GetProcess();
343         // Why do we need to set the current thread by ID here???
344         process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID());
345         process.Resume();
346     }
347 }
348 
349 void
350 SBThread::StepInto (lldb::RunMode stop_other_threads)
351 {
352     if (m_opaque_sp)
353     {
354         bool abort_other_plans = true;
355 
356         StackFrameSP frame_sp(m_opaque_sp->GetStackFrameAtIndex (0));
357 
358         if (frame_sp && frame_sp->HasDebugInformation ())
359         {
360             bool avoid_code_without_debug_info = true;
361             SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
362             m_opaque_sp->QueueThreadPlanForStepRange (abort_other_plans,
363                                                            eStepTypeInto,
364                                                            sc.line_entry.range,
365                                                            sc,
366                                                            stop_other_threads,
367                                                            avoid_code_without_debug_info);
368         }
369         else
370         {
371             m_opaque_sp->QueueThreadPlanForStepSingleInstruction (false,
372                                                                        abort_other_plans,
373                                                                        stop_other_threads);
374         }
375 
376         Process &process = m_opaque_sp->GetProcess();
377         // Why do we need to set the current thread by ID here???
378         process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID());
379         process.Resume();
380 
381     }
382 }
383 
384 void
385 SBThread::StepOut ()
386 {
387     if (m_opaque_sp)
388     {
389         bool abort_other_plans = true;
390         bool stop_other_threads = true;
391 
392         m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, stop_other_threads, eVoteYes, eVoteNoOpinion);
393 
394         Process &process = m_opaque_sp->GetProcess();
395         process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID());
396         process.Resume();
397     }
398 }
399 
400 void
401 SBThread::StepInstruction (bool step_over)
402 {
403     if (m_opaque_sp)
404     {
405         m_opaque_sp->QueueThreadPlanForStepSingleInstruction (step_over, true, true);
406         Process &process = m_opaque_sp->GetProcess();
407         process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID());
408         process.Resume();
409     }
410 }
411 
412 void
413 SBThread::RunToAddress (lldb::addr_t addr)
414 {
415     if (m_opaque_sp)
416     {
417         bool abort_other_plans = true;
418         bool stop_other_threads = true;
419 
420         Address target_addr (NULL, addr);
421 
422         m_opaque_sp->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads);
423         Process &process = m_opaque_sp->GetProcess();
424         process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID());
425         process.Resume();
426     }
427 
428 }
429 
430 SBProcess
431 SBThread::GetProcess ()
432 {
433     SBProcess process;
434     if (m_opaque_sp)
435     {
436         // Have to go up to the target so we can get a shared pointer to our process...
437         process.SetProcess(m_opaque_sp->GetProcess().GetTarget().GetProcessSP());
438     }
439     return process;
440 }
441 
442 uint32_t
443 SBThread::GetNumFrames ()
444 {
445     if (m_opaque_sp)
446         return m_opaque_sp->GetStackFrameCount();
447     return 0;
448 }
449 
450 SBFrame
451 SBThread::GetFrameAtIndex (uint32_t idx)
452 {
453     SBFrame sb_frame;
454     if (m_opaque_sp)
455         sb_frame.SetFrame (m_opaque_sp->GetStackFrameAtIndex (idx));
456     return sb_frame;
457 }
458 
459 const lldb::SBThread &
460 SBThread::operator = (const lldb::SBThread &rhs)
461 {
462     m_opaque_sp = rhs.m_opaque_sp;
463     return *this;
464 }
465 
466 bool
467 SBThread::operator == (const SBThread &rhs) const
468 {
469     return m_opaque_sp.get() == rhs.m_opaque_sp.get();
470 }
471 
472 bool
473 SBThread::operator != (const SBThread &rhs) const
474 {
475     return m_opaque_sp.get() != rhs.m_opaque_sp.get();
476 }
477 
478 lldb_private::Thread *
479 SBThread::GetLLDBObjectPtr ()
480 {
481     return m_opaque_sp.get();
482 }
483 
484 const lldb_private::Thread *
485 SBThread::operator->() const
486 {
487     return m_opaque_sp.get();
488 }
489 
490 const lldb_private::Thread &
491 SBThread::operator*() const
492 {
493     return *m_opaque_sp;
494 }
495 
496 lldb_private::Thread *
497 SBThread::operator->()
498 {
499     return m_opaque_sp.get();
500 }
501 
502 lldb_private::Thread &
503 SBThread::operator*()
504 {
505     return *m_opaque_sp;
506 }
507