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