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