xref: /llvm-project/lldb/source/Commands/CommandObjectThread.cpp (revision 1b72fcb7d1105f500749c2643b34e0bddcf9c0e3)
1 //===-- CommandObjectThread.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 "CommandObjectThread.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Interpreter/Options.h"
17 #include "lldb/Core/State.h"
18 #include "lldb/Core/SourceManager.h"
19 
20 #include "lldb/Interpreter/CommandInterpreter.h"
21 #include "lldb/Interpreter/CommandReturnObject.h"
22 
23 #include "lldb/Target/Process.h"
24 #include "lldb/Target/RegisterContext.h"
25 #include "lldb/Target/Target.h"
26 #include "lldb/Target/Thread.h"
27 #include "lldb/Target/ThreadPlan.h"
28 #include "lldb/Target/ThreadPlanStepInstruction.h"
29 #include "lldb/Target/ThreadPlanStepOut.h"
30 #include "lldb/Target/ThreadPlanStepRange.h"
31 #include "lldb/Target/ThreadPlanStepInRange.h"
32 #include "lldb/Symbol/LineTable.h"
33 #include "lldb/Symbol/LineEntry.h"
34 
35 using namespace lldb;
36 using namespace lldb_private;
37 
38 
39 bool
40 lldb_private::DisplayThreadInfo
41 (
42     CommandInterpreter &interpreter,
43     Stream &strm,
44     Thread *thread,
45     bool only_threads_with_stop_reason,
46     bool show_source
47 )
48 {
49     if (thread)
50     {
51         if (only_threads_with_stop_reason)
52         {
53             if (thread->GetStopInfo() == NULL)
54                 return false;
55         }
56 
57         strm.Indent();
58         strm.Printf("%c ", thread->GetProcess().GetThreadList().GetCurrentThread().get() == thread ? '*' : ' ');
59 
60         // Show one frame with only the first showing source
61         if (show_source)
62         {
63             DisplayFramesForExecutionContext (thread,
64                                               interpreter,
65                                               strm,
66                                               true,
67                                               0,    // Start at first frame
68                                               1,    // Number of frames to show
69                                               false,// Don't show the frame info since we already displayed most of it above...
70                                               1,    // Show source for the first frame
71                                               3,    // lines of source context before
72                                               3);   // lines of source context after
73         }
74         else
75         {
76             thread->DumpInfo (strm,
77                               true, // Dump the stop reason?
78                               true, // Dump the thread name?
79                               true, // Dump the queue name?
80                               0);   // Display context info for stack frame zero
81 
82             strm.EOL();
83         }
84 
85         return true;
86     }
87     return false;
88 }
89 
90 size_t
91 lldb_private::DisplayThreadsInfo
92 (
93     CommandInterpreter &interpreter,
94     ExecutionContext *exe_ctx,
95     CommandReturnObject &result,
96     bool only_threads_with_stop_reason,
97     bool show_source
98 )
99 {
100     StreamString strm;
101 
102     size_t num_thread_infos_dumped = 0;
103 
104     if (!exe_ctx->process)
105         return 0;
106 
107     const size_t num_threads = exe_ctx->process->GetThreadList().GetSize();
108     if (num_threads > 0)
109     {
110 
111         for (uint32_t i = 0; i < num_threads; i++)
112         {
113             Thread *thread = exe_ctx->process->GetThreadList().GetThreadAtIndex(i).get();
114             if (thread)
115             {
116                 if (DisplayThreadInfo (interpreter,
117                                        strm,
118                                        thread,
119                                        only_threads_with_stop_reason,
120                                        show_source))
121                     ++num_thread_infos_dumped;
122             }
123         }
124     }
125 
126     if (num_thread_infos_dumped > 0)
127     {
128         if (num_thread_infos_dumped < num_threads)
129             result.GetOutputStream().Printf("%u of %u threads stopped with reasons:\n", num_thread_infos_dumped, num_threads);
130 
131         result.GetOutputStream().GetString().append(strm.GetString());
132         result.SetStatus (eReturnStatusSuccessFinishNoResult);
133     }
134     return num_thread_infos_dumped;
135 }
136 
137 
138 size_t
139 lldb_private::DisplayFramesForExecutionContext
140 (
141     Thread *thread,
142     CommandInterpreter &interpreter,
143     Stream& strm,
144     bool ascending,
145     uint32_t first_frame,
146     uint32_t num_frames,
147     bool show_frame_info,
148     uint32_t num_frames_with_source,
149     uint32_t source_lines_before,
150     uint32_t source_lines_after
151 )
152 {
153     if (thread == NULL)
154         return 0;
155 
156     size_t num_frames_displayed = 0;
157 
158     if (num_frames == 0)
159         return 0;
160 
161     thread->DumpInfo (strm,
162                       true,     // Dump the stop reason?
163                       true,     // Dump the thread name?
164                       true,     // Dump the queue name?
165                       num_frames > 1 ? UINT32_MAX : first_frame);  // Dump info for the first stack frame if we are showing only on frame
166     strm.EOL();
167     strm.IndentMore();
168 
169     StackFrameSP frame_sp;
170     uint32_t frame_idx = 0;
171 
172     if (ascending)
173     {
174         for (frame_idx = first_frame; frame_idx < first_frame + num_frames; ++frame_idx)
175         {
176             frame_sp = thread->GetStackFrameAtIndex (frame_idx);
177             if (frame_sp.get() == NULL)
178                 break;
179 
180             if (DisplayFrameForExecutionContext (thread,
181                                                  frame_sp.get(),
182                                                  interpreter,
183                                                  strm,
184                                                  show_frame_info,
185                                                  num_frames_with_source > first_frame - frame_idx,
186                                                  source_lines_before,
187                                                  source_lines_after) == false)
188                 break;
189 
190             ++num_frames_displayed;
191         }
192     }
193     else
194     {
195         for (frame_idx = first_frame + num_frames - 1; frame_idx >= first_frame; --frame_idx)
196         {
197             frame_sp = thread->GetStackFrameAtIndex (frame_idx);
198             if (frame_sp == NULL)
199                 break;
200 
201             if (DisplayFrameForExecutionContext (thread,
202                                                  frame_sp.get(),
203                                                  interpreter,
204                                                  strm,
205                                                  show_frame_info,
206                                                  num_frames_with_source > first_frame - frame_idx,
207                                                  source_lines_before,
208                                                  source_lines_after) == false)
209                 break;
210 
211             ++num_frames_displayed;
212         }
213     }
214     strm.IndentLess();
215     return num_frames_displayed;
216 }
217 
218 bool
219 lldb_private::DisplayFrameForExecutionContext
220 (
221     Thread *thread,
222     StackFrame *frame,
223     CommandInterpreter &interpreter,
224     Stream& strm,
225     bool show_frame_info,
226     bool show_source,
227     uint32_t source_lines_before,
228     uint32_t source_lines_after
229 )
230 {
231     // thread and frame must be filled in prior to calling this function
232     if (thread && frame)
233     {
234         if (show_frame_info)
235         {
236             strm.Indent();
237             frame->Dump (&strm, true);
238             strm.EOL();
239         }
240 
241         SymbolContext sc (frame->GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry));
242 
243         if (show_source && sc.comp_unit && sc.line_entry.IsValid())
244         {
245             interpreter.GetDebugger().GetSourceManager().DisplaySourceLinesWithLineNumbers (
246                     sc.line_entry.file,
247                     sc.line_entry.line,
248                     3,
249                     3,
250                     "->",
251                     &strm);
252 
253         }
254         return true;
255     }
256     return false;
257 }
258 
259 
260 //-------------------------------------------------------------------------
261 // CommandObjectThreadBacktrace
262 //-------------------------------------------------------------------------
263 
264 class CommandObjectThreadBacktrace : public CommandObject
265 {
266 public:
267 
268     CommandObjectThreadBacktrace () :
269         CommandObject ("thread backtrace",
270                        "Shows the stack for one or more threads.",
271                        "thread backtrace [<thread-idx>] ...",
272                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
273         m_ascending (true)
274     {
275     }
276 
277     ~CommandObjectThreadBacktrace()
278     {
279     }
280 
281 
282     virtual bool
283     Execute
284     (
285         CommandInterpreter &interpreter,
286         Args& command,
287         CommandReturnObject &result
288     )
289     {
290         if (command.GetArgumentCount() == 0)
291         {
292             ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext());
293             if (exe_ctx.thread)
294             {
295                 bool show_frame_info = true;
296                 uint32_t num_frames_with_source = 0; // Don't show any frasmes with source when backtracing
297                 if (DisplayFramesForExecutionContext (exe_ctx.thread,
298                                                       interpreter,
299                                                       result.GetOutputStream(),
300                                                       m_ascending,
301                                                       0,
302                                                       UINT32_MAX,
303                                                       show_frame_info,
304                                                       num_frames_with_source,
305                                                       3,
306                                                       3))
307                 {
308                     result.SetStatus (eReturnStatusSuccessFinishResult);
309                 }
310             }
311             else
312             {
313                 result.AppendError ("invalid thread");
314                 result.SetStatus (eReturnStatusFailed);
315             }
316         }
317         else
318         {
319             result.AppendError ("backtrace doesn't take arguments (for now)");
320             result.SetStatus (eReturnStatusFailed);
321         }
322         return result.Succeeded();
323     }
324 protected:
325     bool m_ascending;
326 };
327 
328 
329 enum StepScope
330 {
331     eStepScopeSource,
332     eStepScopeInstruction
333 };
334 
335 class CommandObjectThreadStepWithTypeAndScope : public CommandObject
336 {
337 public:
338 
339     class CommandOptions : public Options
340     {
341     public:
342 
343         CommandOptions () :
344             Options()
345         {
346             // Keep default values of all options in one place: ResetOptionValues ()
347             ResetOptionValues ();
348         }
349 
350         virtual
351         ~CommandOptions ()
352         {
353         }
354 
355         virtual Error
356         SetOptionValue (int option_idx, const char *option_arg)
357         {
358             Error error;
359             char short_option = (char) m_getopt_table[option_idx].val;
360 
361             switch (short_option)
362             {
363                 case 'a':
364                 {
365                     bool success;
366                     m_avoid_no_debug =  Args::StringToBoolean (option_arg, true, &success);
367                     if (!success)
368                         error.SetErrorStringWithFormat("Invalid boolean value for option '%c'.\n", short_option);
369                 }
370                 break;
371                 case 'm':
372                 {
373                     bool found_one = false;
374                     OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
375                     m_run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one);
376                     if (!found_one)
377                         error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option);
378                 }
379                 break;
380                 case 'r':
381                 {
382                     m_avoid_regexp.clear();
383                     m_avoid_regexp.assign(option_arg);
384                 }
385                 break;
386                 default:
387                     error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
388                     break;
389 
390             }
391             return error;
392         }
393 
394         void
395         ResetOptionValues ()
396         {
397             Options::ResetOptionValues();
398             m_avoid_no_debug = true;
399             m_run_mode = eOnlyDuringStepping;
400             m_avoid_regexp.clear();
401         }
402 
403         const lldb::OptionDefinition*
404         GetDefinitions ()
405         {
406             return g_option_table;
407         }
408 
409         // Options table: Required for subclasses of Options.
410 
411         static lldb::OptionDefinition g_option_table[];
412 
413         // Instance variables to hold the values for command options.
414         bool m_avoid_no_debug;
415         RunMode m_run_mode;
416         std::string m_avoid_regexp;
417     };
418 
419     CommandObjectThreadStepWithTypeAndScope (const char *name,
420                          const char *help,
421                          const char *syntax,
422                          uint32_t flags,
423                          StepType step_type,
424                          StepScope step_scope) :
425         CommandObject (name, help, syntax, flags),
426         m_step_type (step_type),
427         m_step_scope (step_scope),
428         m_options ()
429     {
430     }
431 
432     virtual
433     ~CommandObjectThreadStepWithTypeAndScope ()
434     {
435     }
436 
437     virtual
438     Options *
439     GetOptions ()
440     {
441         return &m_options;
442     }
443 
444     virtual bool
445     Execute
446     (
447         CommandInterpreter &interpreter,
448         Args& command,
449         CommandReturnObject &result
450     )
451     {
452         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
453         bool synchronous_execution = interpreter.GetSynchronous();
454 
455         if (process == NULL)
456         {
457             result.AppendError ("need a valid process to step");
458             result.SetStatus (eReturnStatusFailed);
459 
460         }
461         else
462         {
463             const uint32_t num_threads = process->GetThreadList().GetSize();
464             Thread *thread = NULL;
465 
466             if (command.GetArgumentCount() == 0)
467             {
468                 thread = process->GetThreadList().GetCurrentThread().get();
469                 if (thread == NULL)
470                 {
471                     result.AppendError ("no current thread in process");
472                     result.SetStatus (eReturnStatusFailed);
473                     return false;
474                 }
475             }
476             else
477             {
478                 const char *thread_idx_cstr = command.GetArgumentAtIndex(0);
479                 uint32_t step_thread_idx = Args::StringToUInt32 (thread_idx_cstr, LLDB_INVALID_INDEX32);
480                 if (step_thread_idx == LLDB_INVALID_INDEX32)
481                 {
482                     result.AppendErrorWithFormat ("Invalid thread index '%s'.\n", thread_idx_cstr);
483                     result.SetStatus (eReturnStatusFailed);
484                     return false;
485                 }
486                 thread = process->GetThreadList().FindThreadByIndexID(step_thread_idx).get();
487                 if (thread == NULL)
488                 {
489                     result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n",
490                                                   step_thread_idx, 0, num_threads);
491                     result.SetStatus (eReturnStatusFailed);
492                     return false;
493                 }
494             }
495 
496             const bool abort_other_plans = false;
497             const lldb::RunMode stop_other_threads = m_options.m_run_mode;
498 
499             // This is a bit unfortunate, but not all the commands in this command object support
500             // only while stepping, so I use the bool for them.
501             bool bool_stop_other_threads;
502             if (m_options.m_run_mode == eAllThreads)
503                 bool_stop_other_threads = false;
504             else
505                 bool_stop_other_threads = true;
506 
507             if (m_step_type == eStepTypeInto)
508             {
509                 StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
510                 ThreadPlan *new_plan;
511 
512                 if (frame->HasDebugInformation ())
513                 {
514                     new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, m_step_type,
515                                                                     frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
516                                                                     frame->GetSymbolContext(eSymbolContextEverything),
517                                                                     stop_other_threads,
518                                                                     m_options.m_avoid_no_debug);
519                     if (new_plan && !m_options.m_avoid_regexp.empty())
520                     {
521                         ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (new_plan);
522                         step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str());
523                     }
524                 }
525                 else
526                     new_plan = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
527 
528                 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
529                 process->Resume ();
530             }
531             else if (m_step_type == eStepTypeOver)
532             {
533                 StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
534                 ThreadPlan *new_plan;
535 
536                 if (frame->HasDebugInformation())
537                     new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans,
538                                                                     m_step_type,
539                                                                     frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
540                                                                     frame->GetSymbolContext(eSymbolContextEverything),
541                                                                     stop_other_threads,
542                                                                     false);
543                 else
544                     new_plan = thread->QueueThreadPlanForStepSingleInstruction (true,
545                                                                                 abort_other_plans,
546                                                                                 bool_stop_other_threads);
547 
548                 // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
549                 // Maybe there should be a parameter to control this.
550                 new_plan->SetOkayToDiscard(false);
551 
552                 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
553                 process->Resume ();
554             }
555             else if (m_step_type == eStepTypeTrace)
556             {
557                 thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
558                 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
559                 process->Resume ();
560             }
561             else if (m_step_type == eStepTypeTraceOver)
562             {
563                 thread->QueueThreadPlanForStepSingleInstruction (true, abort_other_plans, bool_stop_other_threads);
564                 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
565                 process->Resume ();
566             }
567             else if (m_step_type == eStepTypeOut)
568             {
569                 ThreadPlan *new_plan;
570 
571                 new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, bool_stop_other_threads, eVoteYes, eVoteNoOpinion);
572                 // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
573                 // Maybe there should be a parameter to control this.
574                 new_plan->SetOkayToDiscard(false);
575 
576                 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
577                 process->Resume ();
578             }
579             else
580             {
581                 result.AppendError ("step type is not supported");
582                 result.SetStatus (eReturnStatusFailed);
583             }
584             if (synchronous_execution)
585             {
586                 StateType state = process->WaitForProcessToStop (NULL);
587 
588                 //EventSP event_sp;
589                 //StateType state = process->WaitForStateChangedEvents (NULL, event_sp);
590                 //while (! StateIsStoppedState (state))
591                 //  {
592                 //    state = process->WaitForStateChangedEvents (NULL, event_sp);
593                 //  }
594                 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
595                 result.SetDidChangeProcessState (true);
596                 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
597                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
598             }
599         }
600         return result.Succeeded();
601     }
602 
603 protected:
604     StepType m_step_type;
605     StepScope m_step_scope;
606     CommandOptions m_options;
607 };
608 
609 static lldb::OptionEnumValueElement
610 g_tri_running_mode[] =
611 {
612 { eOnlyThisThread,     "thisThread",    "Run only this thread"},
613 { eAllThreads,         "allThreads",    "Run all threads"},
614 { eOnlyDuringStepping, "whileStepping", "Run only this thread while stepping"},
615 { 0, NULL, NULL }
616 };
617 
618 static lldb::OptionEnumValueElement
619 g_duo_running_mode[] =
620 {
621 { eOnlyThisThread,     "thisThread",    "Run only this thread"},
622 { eAllThreads,         "allThreads",    "Run all threads"},
623 { 0, NULL, NULL }
624 };
625 
626 lldb::OptionDefinition
627 CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] =
628 {
629 { LLDB_OPT_SET_1, false, "avoid_no_debug", 'a', required_argument, NULL,               0, "<avoid_no_debug>", "Should step-in step over functions with no debug information"},
630 { LLDB_OPT_SET_1, false, "run_mode",       'm', required_argument, g_tri_running_mode, 0, "<run_mode>",       "Determine how to run other threads while stepping this one"},
631 { LLDB_OPT_SET_1, false, "regexp_to_avoid",'r', required_argument, NULL, 0, "<avoid_regexp>",       "Should step-in step over functions matching this regexp"},
632 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
633 };
634 
635 
636 //-------------------------------------------------------------------------
637 // CommandObjectThreadContinue
638 //-------------------------------------------------------------------------
639 
640 class CommandObjectThreadContinue : public CommandObject
641 {
642 public:
643 
644     CommandObjectThreadContinue () :
645         CommandObject ("thread continue",
646                        "Continues execution of one or more threads in an active process.",
647                        "thread continue <thread-index> [<thread-index> ...]",
648                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
649     {
650     }
651 
652 
653     virtual
654     ~CommandObjectThreadContinue ()
655     {
656     }
657 
658     virtual bool
659     Execute
660     (
661         CommandInterpreter &interpreter,
662         Args& command,
663         CommandReturnObject &result
664     )
665     {
666         bool synchronous_execution = interpreter.GetSynchronous ();
667 
668         if (!interpreter.GetDebugger().GetCurrentTarget().get())
669         {
670             result.AppendError ("invalid target, set executable file using 'file' command");
671             result.SetStatus (eReturnStatusFailed);
672             return false;
673         }
674 
675         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
676         if (process == NULL)
677         {
678             result.AppendError ("no process exists. Cannot continue");
679             result.SetStatus (eReturnStatusFailed);
680             return false;
681         }
682 
683         StateType state = process->GetState();
684         if ((state == eStateCrashed) || (state == eStateStopped) || (state == eStateSuspended))
685         {
686             const uint32_t num_threads = process->GetThreadList().GetSize();
687             uint32_t idx;
688             const size_t argc = command.GetArgumentCount();
689             if (argc > 0)
690             {
691                 std::vector<uint32_t> resume_thread_indexes;
692                 for (uint32_t i=0; i<argc; ++i)
693                 {
694                     idx = Args::StringToUInt32 (command.GetArgumentAtIndex(0), LLDB_INVALID_INDEX32);
695                     if (idx < num_threads)
696                         resume_thread_indexes.push_back(idx);
697                     else
698                         result.AppendWarningWithFormat("Thread index %u out of range.\n", idx);
699                 }
700 
701                 if (resume_thread_indexes.empty())
702                 {
703                     result.AppendError ("no valid thread indexes were specified");
704                     result.SetStatus (eReturnStatusFailed);
705                     return false;
706                 }
707                 else
708                 {
709                     result.AppendMessage ("Resuming thread ");
710                     for (idx=0; idx<num_threads; ++idx)
711                     {
712                         Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
713                         if (find(resume_thread_indexes.begin(), resume_thread_indexes.end(), idx) != resume_thread_indexes.end())
714                         {
715                             result.AppendMessageWithFormat ("%u ", idx);
716                             thread->SetResumeState (eStateRunning);
717                         }
718                         else
719                         {
720                             thread->SetResumeState (eStateSuspended);
721                         }
722                     }
723                     result.AppendMessageWithFormat ("in process %i\n", process->GetID());
724                 }
725             }
726             else
727             {
728                 Thread *current_thread = process->GetThreadList().GetCurrentThread().get();
729                 if (current_thread == NULL)
730                 {
731                     result.AppendError ("the process doesn't have a current thread");
732                     result.SetStatus (eReturnStatusFailed);
733                     return false;
734                 }
735                 // Set the actions that the threads should each take when resuming
736                 for (idx=0; idx<num_threads; ++idx)
737                 {
738                     Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
739                     if (thread == current_thread)
740                     {
741                         result.AppendMessageWithFormat ("Resuming thread 0x%4.4x in process %i\n", thread->GetID(), process->GetID());
742                         thread->SetResumeState (eStateRunning);
743                     }
744                     else
745                     {
746                         thread->SetResumeState (eStateSuspended);
747                     }
748                 }
749             }
750 
751             Error error (process->Resume());
752             if (error.Success())
753             {
754                 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID());
755                 if (synchronous_execution)
756                 {
757                     state = process->WaitForProcessToStop (NULL);
758 
759                     result.SetDidChangeProcessState (true);
760                     result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
761                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
762                 }
763                 else
764                 {
765                     result.SetStatus (eReturnStatusSuccessContinuingNoResult);
766                 }
767             }
768             else
769             {
770                 result.AppendErrorWithFormat("Failed to resume process: %s\n", error.AsCString());
771                 result.SetStatus (eReturnStatusFailed);
772             }
773         }
774         else
775         {
776             result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n",
777                                           StateAsCString(state));
778             result.SetStatus (eReturnStatusFailed);
779         }
780 
781         return result.Succeeded();
782     }
783 
784 };
785 
786 //-------------------------------------------------------------------------
787 // CommandObjectThreadUntil
788 //-------------------------------------------------------------------------
789 
790 class CommandObjectThreadUntil : public CommandObject
791 {
792 public:
793 
794     class CommandOptions : public Options
795     {
796     public:
797         uint32_t m_thread_idx;
798         uint32_t m_frame_idx;
799 
800         CommandOptions () :
801             Options(),
802             m_thread_idx(LLDB_INVALID_THREAD_ID),
803             m_frame_idx(LLDB_INVALID_FRAME_ID)
804         {
805             // Keep default values of all options in one place: ResetOptionValues ()
806             ResetOptionValues ();
807         }
808 
809         virtual
810         ~CommandOptions ()
811         {
812         }
813 
814         virtual Error
815         SetOptionValue (int option_idx, const char *option_arg)
816         {
817             Error error;
818             char short_option = (char) m_getopt_table[option_idx].val;
819 
820             switch (short_option)
821             {
822                 case 't':
823                 {
824                     m_thread_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_INDEX32);
825                     if (m_thread_idx == LLDB_INVALID_INDEX32)
826                     {
827                         error.SetErrorStringWithFormat ("Invalid thread index '%s'.\n", option_arg);
828                     }
829                 }
830                 break;
831                 case 'f':
832                 {
833                     m_frame_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_FRAME_ID);
834                     if (m_frame_idx == LLDB_INVALID_FRAME_ID)
835                     {
836                         error.SetErrorStringWithFormat ("Invalid frame index '%s'.\n", option_arg);
837                     }
838                 }
839                 break;
840                 case 'm':
841                 {
842                     bool found_one = false;
843                     OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
844                     lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one);
845 
846                     if (!found_one)
847                         error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option);
848                     else if (run_mode == eAllThreads)
849                         m_stop_others = false;
850                     else
851                         m_stop_others = true;
852 
853                 }
854                 break;
855                 default:
856                     error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
857                     break;
858 
859             }
860             return error;
861         }
862 
863         void
864         ResetOptionValues ()
865         {
866             Options::ResetOptionValues();
867             m_thread_idx = LLDB_INVALID_THREAD_ID;
868             m_frame_idx = 0;
869             m_stop_others = false;
870         }
871 
872         const lldb::OptionDefinition*
873         GetDefinitions ()
874         {
875             return g_option_table;
876         }
877 
878         uint32_t m_step_thread_idx;
879         bool m_stop_others;
880 
881         // Options table: Required for subclasses of Options.
882 
883         static lldb::OptionDefinition g_option_table[];
884 
885         // Instance variables to hold the values for command options.
886     };
887 
888     CommandObjectThreadUntil () :
889         CommandObject ("thread until",
890                        "Runs the current or specified thread until it reaches a given line number or leaves the current function.",
891                        "thread until [<cmd-options>] <line-number>",
892                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
893         m_options ()
894     {
895     }
896 
897 
898     virtual
899     ~CommandObjectThreadUntil ()
900     {
901     }
902 
903     virtual
904     Options *
905     GetOptions ()
906     {
907         return &m_options;
908     }
909 
910     virtual bool
911     Execute
912     (
913         CommandInterpreter &interpreter,
914         Args& command,
915         CommandReturnObject &result
916     )
917     {
918         bool synchronous_execution = interpreter.GetSynchronous ();
919 
920         if (!interpreter.GetDebugger().GetCurrentTarget().get())
921         {
922             result.AppendError ("invalid target, set executable file using 'file' command");
923             result.SetStatus (eReturnStatusFailed);
924             return false;
925         }
926 
927         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
928         if (process == NULL)
929         {
930             result.AppendError ("need a valid process to step");
931             result.SetStatus (eReturnStatusFailed);
932 
933         }
934         else
935         {
936             Thread *thread = NULL;
937             uint32_t line_number;
938 
939             if (command.GetArgumentCount() != 1)
940             {
941                 result.AppendErrorWithFormat ("No line number provided:\n%s", GetSyntax());
942                 result.SetStatus (eReturnStatusFailed);
943                 return false;
944             }
945 
946             line_number = Args::StringToUInt32 (command.GetArgumentAtIndex(0), UINT32_MAX);
947             if (line_number == UINT32_MAX)
948             {
949                 result.AppendErrorWithFormat ("Invalid line number: '%s'.\n", command.GetArgumentAtIndex(0));
950                 result.SetStatus (eReturnStatusFailed);
951                 return false;
952             }
953 
954             if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID)
955             {
956                 thread = process->GetThreadList().GetCurrentThread().get();
957             }
958             else
959             {
960                 thread = process->GetThreadList().GetThreadAtIndex(m_options.m_thread_idx).get();
961             }
962 
963             if (thread == NULL)
964             {
965                 const uint32_t num_threads = process->GetThreadList().GetSize();
966                 result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n", m_options.m_thread_idx, 0, num_threads);
967                 result.SetStatus (eReturnStatusFailed);
968                 return false;
969             }
970 
971             const bool abort_other_plans = true;
972 
973             StackFrame *frame = thread->GetStackFrameAtIndex(m_options.m_frame_idx).get();
974             if (frame == NULL)
975             {
976 
977                 result.AppendErrorWithFormat ("Frame index %u is out of range for thread %u.\n", m_options.m_frame_idx, m_options.m_thread_idx);
978                 result.SetStatus (eReturnStatusFailed);
979                 return false;
980             }
981 
982             ThreadPlan *new_plan;
983 
984             if (frame->HasDebugInformation ())
985             {
986                 // Finally we got here...  Translate the given line number to a bunch of addresses:
987                 SymbolContext sc(frame->GetSymbolContext (eSymbolContextCompUnit));
988                 LineTable *line_table = NULL;
989                 if (sc.comp_unit)
990                     line_table = sc.comp_unit->GetLineTable();
991 
992                 if (line_table == NULL)
993                 {
994                     result.AppendErrorWithFormat ("Failed to resolve the line table for frame %u of thread index %u.\n",
995                                                  m_options.m_frame_idx, m_options.m_thread_idx);
996                     result.SetStatus (eReturnStatusFailed);
997                     return false;
998                 }
999 
1000                 LineEntry function_start;
1001                 uint32_t index_ptr = 0, end_ptr;
1002                 std::vector<addr_t> address_list;
1003 
1004                 // Find the beginning & end index of the
1005                 AddressRange fun_addr_range = sc.function->GetAddressRange();
1006                 Address fun_start_addr = fun_addr_range.GetBaseAddress();
1007                 line_table->FindLineEntryByAddress (fun_start_addr, function_start, &index_ptr);
1008 
1009                 Address fun_end_addr(fun_start_addr.GetSection(), fun_start_addr.GetOffset() + fun_addr_range.GetByteSize());
1010                 line_table->FindLineEntryByAddress (fun_end_addr, function_start, &end_ptr);
1011 
1012                 while (index_ptr <= end_ptr)
1013                 {
1014                     LineEntry line_entry;
1015                     index_ptr = sc.comp_unit->FindLineEntry(index_ptr, line_number, sc.comp_unit, &line_entry);
1016                     if (index_ptr == UINT32_MAX)
1017                         break;
1018 
1019                     addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(process);
1020                     if (address != LLDB_INVALID_ADDRESS)
1021                         address_list.push_back (address);
1022                     index_ptr++;
1023                 }
1024 
1025                 new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, &address_list.front(), address_list.size(), m_options.m_stop_others);
1026                 new_plan->SetOkayToDiscard(false);
1027             }
1028             else
1029             {
1030                 result.AppendErrorWithFormat ("Frame index %u of thread %u has no debug information.\n", m_options.m_frame_idx, m_options.m_thread_idx);
1031                 result.SetStatus (eReturnStatusFailed);
1032                 return false;
1033 
1034             }
1035 
1036             process->GetThreadList().SetCurrentThreadByID (m_options.m_thread_idx);
1037             Error error (process->Resume ());
1038             if (error.Success())
1039             {
1040                 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID());
1041                 if (synchronous_execution)
1042                 {
1043                     StateType state = process->WaitForProcessToStop (NULL);
1044 
1045                     result.SetDidChangeProcessState (true);
1046                     result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
1047                     result.SetStatus (eReturnStatusSuccessFinishNoResult);
1048                 }
1049                 else
1050                 {
1051                     result.SetStatus (eReturnStatusSuccessContinuingNoResult);
1052                 }
1053             }
1054             else
1055             {
1056                 result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString());
1057                 result.SetStatus (eReturnStatusFailed);
1058             }
1059 
1060         }
1061         return result.Succeeded();
1062     }
1063 protected:
1064     CommandOptions m_options;
1065 
1066 };
1067 
1068 lldb::OptionDefinition
1069 CommandObjectThreadUntil::CommandOptions::g_option_table[] =
1070 {
1071 { LLDB_OPT_SET_1, false, "frame",   'f', required_argument, NULL,               0, "<frame>",   "Frame index for until operation - defaults to 0"},
1072 { LLDB_OPT_SET_1, false, "thread",  't', required_argument, NULL,               0, "<thread>",  "Thread index for the thread for until operation"},
1073 { LLDB_OPT_SET_1, false, "run_mode",'m', required_argument, g_duo_running_mode, 0, "<run_mode>","Determine how to run other threads while stepping this one"},
1074 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
1075 };
1076 
1077 
1078 //-------------------------------------------------------------------------
1079 // CommandObjectThreadSelect
1080 //-------------------------------------------------------------------------
1081 
1082 class CommandObjectThreadSelect : public CommandObject
1083 {
1084 public:
1085 
1086     CommandObjectThreadSelect () :
1087         CommandObject ("thread select",
1088                          "Selects a threads as the currently active thread.",
1089                          "thread select <thread-index>",
1090                          eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
1091     {
1092     }
1093 
1094 
1095     virtual
1096     ~CommandObjectThreadSelect ()
1097     {
1098     }
1099 
1100     virtual bool
1101     Execute
1102     (
1103         CommandInterpreter &interpreter,
1104         Args& command,
1105         CommandReturnObject &result
1106     )
1107     {
1108         Process *process = interpreter.GetDebugger().GetExecutionContext().process;
1109         if (process == NULL)
1110         {
1111             result.AppendError ("no process");
1112             result.SetStatus (eReturnStatusFailed);
1113             return false;
1114         }
1115         else if (command.GetArgumentCount() != 1)
1116         {
1117             result.AppendErrorWithFormat("'%s' takes exactly one thread index argument:\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
1118             result.SetStatus (eReturnStatusFailed);
1119             return false;
1120         }
1121 
1122         uint32_t index_id = Args::StringToUInt32(command.GetArgumentAtIndex(0), 0, 0);
1123 
1124         Thread *new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get();
1125         if (new_thread == NULL)
1126         {
1127             result.AppendErrorWithFormat ("Invalid thread #%s.\n", command.GetArgumentAtIndex(0));
1128             result.SetStatus (eReturnStatusFailed);
1129             return false;
1130         }
1131 
1132         process->GetThreadList().SetCurrentThreadByID(new_thread->GetID());
1133 
1134         DisplayThreadInfo (interpreter,
1135                            result.GetOutputStream(),
1136                            new_thread,
1137                            false,
1138                            true);
1139 
1140         return result.Succeeded();
1141     }
1142 
1143 };
1144 
1145 
1146 //-------------------------------------------------------------------------
1147 // CommandObjectThreadList
1148 //-------------------------------------------------------------------------
1149 
1150 class CommandObjectThreadList : public CommandObject
1151 {
1152 public:
1153 
1154 
1155     CommandObjectThreadList ():
1156         CommandObject ("thread list",
1157                        "Shows a summary of all current threads in a process.",
1158                        "thread list",
1159                        eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
1160     {
1161     }
1162 
1163     ~CommandObjectThreadList()
1164     {
1165     }
1166 
1167     bool
1168     Execute
1169     (
1170         CommandInterpreter &interpreter,
1171         Args& command,
1172         CommandReturnObject &result
1173     )
1174     {
1175         StreamString &strm = result.GetOutputStream();
1176         result.SetStatus (eReturnStatusSuccessFinishNoResult);
1177         ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext());
1178         if (exe_ctx.process)
1179         {
1180             const StateType state = exe_ctx.process->GetState();
1181 
1182             if (StateIsStoppedState(state))
1183             {
1184                 if (state == eStateExited)
1185                 {
1186                     int exit_status = exe_ctx.process->GetExitStatus();
1187                     const char *exit_description = exe_ctx.process->GetExitDescription();
1188                     strm.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n",
1189                                           exe_ctx.process->GetID(),
1190                                           exit_status,
1191                                           exit_status,
1192                                           exit_description ? exit_description : "");
1193                 }
1194                 else
1195                 {
1196                     strm.Printf ("Process %d state is %s\n", exe_ctx.process->GetID(), StateAsCString (state));
1197                     if (exe_ctx.thread == NULL)
1198                         exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
1199                     if (exe_ctx.thread != NULL)
1200                     {
1201                         DisplayThreadsInfo (interpreter, &exe_ctx, result, false, false);
1202                     }
1203                     else
1204                     {
1205                         result.AppendError ("no valid thread found in current process");
1206                         result.SetStatus (eReturnStatusFailed);
1207                     }
1208                 }
1209             }
1210             else
1211             {
1212                 result.AppendError ("process is currently running");
1213                 result.SetStatus (eReturnStatusFailed);
1214             }
1215         }
1216         else
1217         {
1218             result.AppendError ("no current location or status available");
1219             result.SetStatus (eReturnStatusFailed);
1220         }
1221         return result.Succeeded();
1222     }
1223 };
1224 
1225 //-------------------------------------------------------------------------
1226 // CommandObjectMultiwordThread
1227 //-------------------------------------------------------------------------
1228 
1229 CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter &interpreter) :
1230     CommandObjectMultiword ("thread",
1231                             "A set of commands for operating on one or more thread within a running process.",
1232                             "thread <subcommand> [<subcommand-options>]")
1233 {
1234     LoadSubCommand (interpreter, "backtrace",  CommandObjectSP (new CommandObjectThreadBacktrace ()));
1235     LoadSubCommand (interpreter, "continue",   CommandObjectSP (new CommandObjectThreadContinue ()));
1236     LoadSubCommand (interpreter, "list",       CommandObjectSP (new CommandObjectThreadList ()));
1237     LoadSubCommand (interpreter, "select",     CommandObjectSP (new CommandObjectThreadSelect ()));
1238     LoadSubCommand (interpreter, "until",      CommandObjectSP (new CommandObjectThreadUntil ()));
1239     LoadSubCommand (interpreter, "step-in",    CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
1240                                                     "thread step-in",
1241                                                      "Source level single step in in specified thread (current thread, if none specified).",
1242                                                      "thread step-in [<thread-id>]",
1243                                                      eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
1244                                                      eStepTypeInto,
1245                                                      eStepScopeSource)));
1246 
1247     LoadSubCommand (interpreter, "step-out",    CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-out",
1248                                                                                       "Source level single step out in specified thread (current thread, if none specified).",
1249                                                                                       "thread step-out [<thread-id>]",
1250                                                                                       eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
1251                                                                                       eStepTypeOut,
1252                                                                                       eStepScopeSource)));
1253 
1254     LoadSubCommand (interpreter, "step-over",   CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-over",
1255                                                                                       "Source level single step over in specified thread (current thread, if none specified).",
1256                                                                                       "thread step-over [<thread-id>]",
1257                                                                                       eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
1258                                                                                       eStepTypeOver,
1259                                                                                       eStepScopeSource)));
1260 
1261     LoadSubCommand (interpreter, "step-inst",   CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst",
1262                                                                                       "Single step one instruction in specified thread (current thread, if none specified).",
1263                                                                                       "thread step-inst [<thread-id>]",
1264                                                                                       eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
1265                                                                                       eStepTypeTrace,
1266                                                                                       eStepScopeInstruction)));
1267 
1268     LoadSubCommand (interpreter, "step-inst-over", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst-over",
1269                                                                                       "Single step one instruction in specified thread (current thread, if none specified), stepping over calls.",
1270                                                                                       "thread step-inst-over [<thread-id>]",
1271                                                                                       eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
1272                                                                                       eStepTypeTraceOver,
1273                                                                                       eStepScopeInstruction)));
1274 }
1275 
1276 CommandObjectMultiwordThread::~CommandObjectMultiwordThread ()
1277 {
1278 }
1279 
1280 
1281