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