blob: 76d13e8cb547951b8ceef3edd8eac2852f1d2b82 [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),
Greg Clayton8f5fd6b2010-06-12 18:59:55 +0000515 stop_other_threads,
516 m_options.m_avoid_no_debug);
Chris Lattner24943d22010-06-08 16:52:24 +0000517 }
518 else
519 new_plan = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
520
521 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
522 process->Resume ();
523 }
524 else if (m_step_type == eStepTypeOver)
525 {
526 StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
527 ThreadPlan *new_plan;
528
529 if (frame->HasDebugInformation())
530 new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans,
531 m_step_type,
532 frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
533 frame->GetSymbolContext(eSymbolContextEverything),
Greg Clayton8f5fd6b2010-06-12 18:59:55 +0000534 stop_other_threads,
535 false);
Chris Lattner24943d22010-06-08 16:52:24 +0000536 else
537 new_plan = thread->QueueThreadPlanForStepSingleInstruction (true,
538 abort_other_plans,
539 bool_stop_other_threads);
540
541 // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
542 // Maybe there should be a parameter to control this.
543 new_plan->SetOkayToDiscard(false);
544
545 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
546 process->Resume ();
547 }
548 else if (m_step_type == eStepTypeTrace)
549 {
550 thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
551 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
552 process->Resume ();
553 }
554 else if (m_step_type == eStepTypeTraceOver)
555 {
556 thread->QueueThreadPlanForStepSingleInstruction (true, abort_other_plans, bool_stop_other_threads);
557 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
558 process->Resume ();
559 }
560 else if (m_step_type == eStepTypeOut)
561 {
562 ThreadPlan *new_plan;
563
564 new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, bool_stop_other_threads, eVoteYes, eVoteNoOpinion);
565 // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
566 // Maybe there should be a parameter to control this.
567 new_plan->SetOkayToDiscard(false);
568
569 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
570 process->Resume ();
571 }
572 else
573 {
574 result.AppendError ("step type is not supported");
575 result.SetStatus (eReturnStatusFailed);
576 }
577 if (synchronous_execution)
578 {
579 StateType state = process->WaitForProcessToStop (NULL);
580
581 //EventSP event_sp;
582 //StateType state = process->WaitForStateChangedEvents (NULL, event_sp);
583 //while (! StateIsStoppedState (state))
584 // {
585 // state = process->WaitForStateChangedEvents (NULL, event_sp);
586 // }
587 process->GetThreadList().SetCurrentThreadByID (thread->GetID());
588 result.SetDidChangeProcessState (true);
589 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
590 result.SetStatus (eReturnStatusSuccessFinishNoResult);
591 }
592 }
593 return result.Succeeded();
594 }
595
596protected:
597 StepType m_step_type;
598 StepScope m_step_scope;
599 CommandOptions m_options;
600};
601
602static lldb::OptionEnumValueElement
603g_tri_running_mode[] =
604{
605{ eOnlyThisThread, "thisThread", "Run only this thread"},
606{ eAllThreads, "allThreads", "Run all threads"},
607{ eOnlyDuringStepping, "whileStepping", "Run only this thread while stepping"},
608{ 0, NULL, NULL }
609};
610
611static lldb::OptionEnumValueElement
612g_duo_running_mode[] =
613{
614{ eOnlyThisThread, "thisThread", "Run only this thread"},
615{ eAllThreads, "allThreads", "Run all threads"},
616{ 0, NULL, NULL }
617};
618
619lldb::OptionDefinition
620CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] =
621{
Jim Ingham34e9a982010-06-15 18:47:14 +0000622{ 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"},
623{ 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 +0000624{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
625};
626
627
628//-------------------------------------------------------------------------
629// CommandObjectThreadContinue
630//-------------------------------------------------------------------------
631
632class CommandObjectThreadContinue : public CommandObject
633{
634public:
635
636 CommandObjectThreadContinue () :
637 CommandObject ("thread continue",
638 "Continues execution of one or more threads in an active process.",
639 "thread continue <thread-index> [<thread-index> ...]",
640 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
641 {
642 }
643
644
645 virtual
646 ~CommandObjectThreadContinue ()
647 {
648 }
649
650 virtual bool
651 Execute (Args& command,
652 CommandContext *context,
653 CommandInterpreter *interpreter,
654 CommandReturnObject &result)
655 {
656 bool synchronous_execution = interpreter->GetSynchronous ();
657
658 if (!context->GetTarget())
659 {
660 result.AppendError ("invalid target, set executable file using 'file' command");
661 result.SetStatus (eReturnStatusFailed);
662 return false;
663 }
664
665 Process *process = context->GetExecutionContext().process;
666 if (process == NULL)
667 {
668 result.AppendError ("no process exists. Cannot continue");
669 result.SetStatus (eReturnStatusFailed);
670 return false;
671 }
672
673 StateType state = process->GetState();
674 if ((state == eStateCrashed) || (state == eStateStopped) || (state == eStateSuspended))
675 {
676 const uint32_t num_threads = process->GetThreadList().GetSize();
677 uint32_t idx;
678 const size_t argc = command.GetArgumentCount();
679 if (argc > 0)
680 {
681 std::vector<uint32_t> resume_thread_indexes;
682 for (uint32_t i=0; i<argc; ++i)
683 {
684 idx = Args::StringToUInt32 (command.GetArgumentAtIndex(0), LLDB_INVALID_INDEX32);
685 if (idx < num_threads)
686 resume_thread_indexes.push_back(idx);
687 else
688 result.AppendWarningWithFormat("Thread index %u out of range.\n", idx);
689 }
690
691 if (resume_thread_indexes.empty())
692 {
693 result.AppendError ("no valid thread indexes were specified");
694 result.SetStatus (eReturnStatusFailed);
695 return false;
696 }
697 else
698 {
699 result.AppendMessage ("Resuming thread ");
700 for (idx=0; idx<num_threads; ++idx)
701 {
702 Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
703 if (find(resume_thread_indexes.begin(), resume_thread_indexes.end(), idx) != resume_thread_indexes.end())
704 {
705 result.AppendMessageWithFormat ("%u ", idx);
706 thread->SetResumeState (eStateRunning);
707 }
708 else
709 {
710 thread->SetResumeState (eStateSuspended);
711 }
712 }
713 result.AppendMessageWithFormat ("in process %i\n", process->GetID());
714 }
715 }
716 else
717 {
718 Thread *current_thread = process->GetThreadList().GetCurrentThread().get();
719 if (current_thread == NULL)
720 {
721 result.AppendError ("the process doesn't have a current thread");
722 result.SetStatus (eReturnStatusFailed);
723 return false;
724 }
725 // Set the actions that the threads should each take when resuming
726 for (idx=0; idx<num_threads; ++idx)
727 {
728 Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
729 if (thread == current_thread)
730 {
731 result.AppendMessageWithFormat ("Resuming thread 0x%4.4x in process %i\n", thread->GetID(), process->GetID());
732 thread->SetResumeState (eStateRunning);
733 }
734 else
735 {
736 thread->SetResumeState (eStateSuspended);
737 }
738 }
739 }
740
741 Error error (process->Resume());
742 if (error.Success())
743 {
744 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID());
745 if (synchronous_execution)
746 {
747 StateType state = process->WaitForProcessToStop (NULL);
748
749 result.SetDidChangeProcessState (true);
750 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
751 result.SetStatus (eReturnStatusSuccessFinishNoResult);
752 }
753 else
754 {
755 result.SetStatus (eReturnStatusSuccessContinuingNoResult);
756 }
757 }
758 else
759 {
760 result.AppendErrorWithFormat("Failed to resume process: %s\n", error.AsCString());
761 result.SetStatus (eReturnStatusFailed);
762 }
763 }
764 else
765 {
766 result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n",
767 StateAsCString(state));
768 result.SetStatus (eReturnStatusFailed);
769 }
770
771 return result.Succeeded();
772 }
773
774};
775
776//-------------------------------------------------------------------------
777// CommandObjectThreadUntil
778//-------------------------------------------------------------------------
779
780class CommandObjectThreadUntil : public CommandObject
781{
782public:
783
784 class CommandOptions : public Options
785 {
786 public:
787 uint32_t m_thread_idx;
788 uint32_t m_frame_idx;
789
790 CommandOptions () :
791 Options(),
792 m_thread_idx(LLDB_INVALID_THREAD_ID),
793 m_frame_idx(LLDB_INVALID_FRAME_ID)
794 {
795 // Keep default values of all options in one place: ResetOptionValues ()
796 ResetOptionValues ();
797 }
798
799 virtual
800 ~CommandOptions ()
801 {
802 }
803
804 virtual Error
805 SetOptionValue (int option_idx, const char *option_arg)
806 {
807 Error error;
808 char short_option = (char) m_getopt_table[option_idx].val;
809
810 switch (short_option)
811 {
812 case 't':
813 {
814 uint32_t m_thread_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_INDEX32);
815 if (m_thread_idx == LLDB_INVALID_INDEX32)
816 {
817 error.SetErrorStringWithFormat ("Invalid thread index '%s'.\n", option_arg);
818 }
819 }
820 break;
821 case 'f':
822 {
823 m_frame_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_FRAME_ID);
824 if (m_frame_idx == LLDB_INVALID_FRAME_ID)
825 {
826 error.SetErrorStringWithFormat ("Invalid frame index '%s'.\n", option_arg);
827 }
828 }
829 break;
830 case 'm':
831 {
832 bool found_one = false;
833 OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
834 lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one);
835
836 if (!found_one)
837 error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option);
838 else if (run_mode == eAllThreads)
839 m_stop_others = false;
840 else
841 m_stop_others = true;
842
843 }
844 break;
845 default:
846 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
847 break;
848
849 }
850 return error;
851 }
852
853 void
854 ResetOptionValues ()
855 {
856 Options::ResetOptionValues();
857 m_thread_idx = LLDB_INVALID_THREAD_ID;
858 m_frame_idx = 0;
859 m_stop_others = false;
860 }
861
862 const lldb::OptionDefinition*
863 GetDefinitions ()
864 {
865 return g_option_table;
866 }
867
868 uint32_t m_step_thread_idx;
869 bool m_stop_others;
870
871 // Options table: Required for subclasses of Options.
872
873 static lldb::OptionDefinition g_option_table[];
874
875 // Instance variables to hold the values for command options.
876 };
877
878 CommandObjectThreadUntil () :
879 CommandObject ("thread until",
880 "Runs the current or specified thread until it reaches a given line number or leaves the current function.",
881 "thread until [<cmd-options>] <line-number>",
882 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
883 m_options ()
884 {
885 }
886
887
888 virtual
889 ~CommandObjectThreadUntil ()
890 {
891 }
892
893 virtual
894 Options *
895 GetOptions ()
896 {
897 return &m_options;
898 }
899
900 virtual bool
901 Execute (Args& command,
902 CommandContext *context,
903 CommandInterpreter *interpreter,
904 CommandReturnObject &result)
905 {
906 bool synchronous_execution = interpreter->GetSynchronous ();
907
908 if (!context->GetTarget())
909 {
910 result.AppendError ("invalid target, set executable file using 'file' command");
911 result.SetStatus (eReturnStatusFailed);
912 return false;
913 }
914
915 Process *process = context->GetExecutionContext().process;
916 if (process == NULL)
917 {
918 result.AppendError ("need a valid process to step");
919 result.SetStatus (eReturnStatusFailed);
920
921 }
922 else
923 {
924 Thread *thread = NULL;
925 uint32_t line_number;
926
927 if (command.GetArgumentCount() != 1)
928 {
929 result.AppendErrorWithFormat ("No line number provided:\n%s", GetSyntax());
930 result.SetStatus (eReturnStatusFailed);
931 return false;
932 }
933
934 line_number = Args::StringToUInt32 (command.GetArgumentAtIndex(0), UINT32_MAX);
935 if (line_number == UINT32_MAX)
936 {
937 result.AppendErrorWithFormat ("Invalid line number: '%s'.\n", command.GetArgumentAtIndex(0));
938 result.SetStatus (eReturnStatusFailed);
939 return false;
940 }
941
942 if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID)
943 {
944 thread = process->GetThreadList().GetCurrentThread().get();
945 }
946 else
947 {
948 thread = process->GetThreadList().GetThreadAtIndex(m_options.m_thread_idx).get();
949 }
950
951 if (thread == NULL)
952 {
953 const uint32_t num_threads = process->GetThreadList().GetSize();
954 result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n", m_options.m_thread_idx, 0, num_threads);
955 result.SetStatus (eReturnStatusFailed);
956 return false;
957 }
958
959 const bool abort_other_plans = true;
960
961 StackFrame *frame = thread->GetStackFrameAtIndex(m_options.m_frame_idx).get();
962 if (frame == NULL)
963 {
964
965 result.AppendErrorWithFormat ("Frame index %u is out of range for thread %u.\n", m_options.m_frame_idx, m_options.m_thread_idx);
966 result.SetStatus (eReturnStatusFailed);
967 return false;
968 }
969
970 ThreadPlan *new_plan;
971
972 if (frame->HasDebugInformation ())
973 {
974 // Finally we got here... Translate the given line number to a bunch of addresses:
975 SymbolContext sc(frame->GetSymbolContext (eSymbolContextCompUnit));
976 LineTable *line_table = NULL;
977 if (sc.comp_unit)
978 line_table = sc.comp_unit->GetLineTable();
979
980 if (line_table == NULL)
981 {
982 result.AppendErrorWithFormat ("Failed to resolve the line table for frame %u of thread index %u.\n",
983 m_options.m_frame_idx, m_options.m_thread_idx);
984 result.SetStatus (eReturnStatusFailed);
985 return false;
986 }
987
988 LineEntry function_start;
989 uint32_t index_ptr = 0, end_ptr;
990 std::vector<addr_t> address_list;
991
992 // Find the beginning & end index of the
993 AddressRange fun_addr_range = sc.function->GetAddressRange();
994 Address fun_start_addr = fun_addr_range.GetBaseAddress();
995 line_table->FindLineEntryByAddress (fun_start_addr, function_start, &index_ptr);
996
997 Address fun_end_addr(fun_start_addr.GetSection(), fun_start_addr.GetOffset() + fun_addr_range.GetByteSize());
998 line_table->FindLineEntryByAddress (fun_end_addr, function_start, &end_ptr);
999
1000 while (index_ptr <= end_ptr)
1001 {
1002 LineEntry line_entry;
1003 index_ptr = sc.comp_unit->FindLineEntry(index_ptr, line_number, sc.comp_unit, &line_entry);
1004 if (index_ptr == UINT32_MAX)
1005 break;
1006
1007 addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(process);
1008 if (address != LLDB_INVALID_ADDRESS)
1009 address_list.push_back (address);
1010 index_ptr++;
1011 }
1012
1013 new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, address_list.data(), address_list.size(), m_options.m_stop_others);
1014 new_plan->SetOkayToDiscard(false);
1015 }
1016 else
1017 {
1018 result.AppendErrorWithFormat ("Frame index %u of thread %u has no debug information.\n", m_options.m_frame_idx, m_options.m_thread_idx);
1019 result.SetStatus (eReturnStatusFailed);
1020 return false;
1021
1022 }
1023
1024 process->GetThreadList().SetCurrentThreadByID (m_options.m_thread_idx);
1025 Error error (process->Resume ());
1026 if (error.Success())
1027 {
1028 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID());
1029 if (synchronous_execution)
1030 {
1031 StateType state = process->WaitForProcessToStop (NULL);
1032
1033 result.SetDidChangeProcessState (true);
1034 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
1035 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1036 }
1037 else
1038 {
1039 result.SetStatus (eReturnStatusSuccessContinuingNoResult);
1040 }
1041 }
1042 else
1043 {
1044 result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString());
1045 result.SetStatus (eReturnStatusFailed);
1046 }
1047
1048 }
1049 return result.Succeeded();
1050 }
1051protected:
1052 CommandOptions m_options;
1053
1054};
1055
1056lldb::OptionDefinition
1057CommandObjectThreadUntil::CommandOptions::g_option_table[] =
1058{
Jim Ingham34e9a982010-06-15 18:47:14 +00001059{ LLDB_OPT_SET_1, true, "frame", 'f', required_argument, NULL, 0, "<frame>", "Frame index for until operation - defaults to 0"},
1060{ LLDB_OPT_SET_1, true, "thread", 't', required_argument, NULL, 0, "<thread>", "Thread index for the thread for until operation"},
1061{ 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 +00001062{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
1063};
1064
1065
1066//-------------------------------------------------------------------------
1067// CommandObjectThreadSelect
1068//-------------------------------------------------------------------------
1069
1070class CommandObjectThreadSelect : public CommandObject
1071{
1072public:
1073
1074 CommandObjectThreadSelect () :
1075 CommandObject ("thread select",
1076 "Selects a threads as the currently active thread.",
1077 "thread select <thread-index>",
1078 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
1079 {
1080 }
1081
1082
1083 virtual
1084 ~CommandObjectThreadSelect ()
1085 {
1086 }
1087
1088 virtual bool
1089 Execute (Args& command,
1090 CommandContext *context,
1091 CommandInterpreter *interpreter,
1092 CommandReturnObject &result)
1093 {
1094 Process *process = context->GetExecutionContext().process;
1095 if (process == NULL)
1096 {
1097 result.AppendError ("no process");
1098 result.SetStatus (eReturnStatusFailed);
1099 return false;
1100 }
1101 else if (command.GetArgumentCount() != 1)
1102 {
1103 result.AppendErrorWithFormat("'%s' takes exactly one thread index argument:\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
1104 result.SetStatus (eReturnStatusFailed);
1105 return false;
1106 }
1107
1108 uint32_t index_id = Args::StringToUInt32(command.GetArgumentAtIndex(0), 0, 0);
1109
1110 Thread *new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get();
1111 if (new_thread == NULL)
1112 {
1113 result.AppendErrorWithFormat ("Invalid thread #%s.\n", command.GetArgumentAtIndex(0));
1114 result.SetStatus (eReturnStatusFailed);
1115 return false;
1116 }
1117
1118 process->GetThreadList().SetCurrentThreadByID(new_thread->GetID());
1119
1120 DisplayThreadInfo (interpreter,
1121 result.GetOutputStream(),
1122 new_thread,
1123 false,
1124 true);
1125
1126 return result.Succeeded();
1127 }
1128
1129};
1130
1131
1132//-------------------------------------------------------------------------
1133// CommandObjectThreadList
1134//-------------------------------------------------------------------------
1135
1136CommandObjectThreadList::CommandObjectThreadList ():
1137 CommandObject ("thread list",
1138 "Shows a summary of all current threads in a process.",
1139 "thread list",
1140 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
1141{
1142}
1143
1144CommandObjectThreadList::~CommandObjectThreadList()
1145{
1146}
1147
1148bool
1149CommandObjectThreadList::Execute
1150(
1151 Args& command,
1152 CommandContext *context,
1153 CommandInterpreter *interpreter,
1154 CommandReturnObject &result
1155)
1156{
1157 StreamString &strm = result.GetOutputStream();
1158 result.SetStatus (eReturnStatusSuccessFinishNoResult);
1159 ExecutionContext exe_ctx(context->GetExecutionContext());
1160 if (exe_ctx.process)
1161 {
1162 const StateType state = exe_ctx.process->GetState();
1163
1164 if (StateIsStoppedState(state))
1165 {
1166 if (state == eStateExited)
1167 {
1168 int exit_status = exe_ctx.process->GetExitStatus();
1169 const char *exit_description = exe_ctx.process->GetExitDescription();
1170 strm.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n",
1171 exe_ctx.process->GetID(),
1172 exit_status,
1173 exit_status,
1174 exit_description ? exit_description : "");
1175 }
1176 else
1177 {
1178 strm.Printf ("Process %d state is %s\n", exe_ctx.process->GetID(), StateAsCString (state));
1179 if (exe_ctx.thread == NULL)
1180 exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
1181 if (exe_ctx.thread != NULL)
1182 {
1183 DisplayThreadsInfo (interpreter, &exe_ctx, result, false, false);
1184 }
1185 else
1186 {
1187 result.AppendError ("no valid thread found in current process");
1188 result.SetStatus (eReturnStatusFailed);
1189 }
1190 }
1191 }
1192 else
1193 {
1194 result.AppendError ("process is currently running");
1195 result.SetStatus (eReturnStatusFailed);
1196 }
1197 }
1198 else
1199 {
1200 result.AppendError ("no current location or status available");
1201 result.SetStatus (eReturnStatusFailed);
1202 }
1203 return result.Succeeded();
1204}
1205
1206//-------------------------------------------------------------------------
1207// CommandObjectMultiwordThread
1208//-------------------------------------------------------------------------
1209
1210CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter *interpreter) :
1211 CommandObjectMultiword ("thread",
1212 "A set of commands for operating on one or more thread within a running process.",
1213 "thread <subcommand> [<subcommand-options>]")
1214{
1215 LoadSubCommand (CommandObjectSP (new CommandObjectThreadBacktrace ()), "backtrace", interpreter);
1216 LoadSubCommand (CommandObjectSP (new CommandObjectThreadContinue ()), "continue", interpreter);
1217 LoadSubCommand (CommandObjectSP (new CommandObjectThreadList ()), "list", interpreter);
1218 LoadSubCommand (CommandObjectSP (new CommandObjectThreadSelect ()), "select", interpreter);
1219 LoadSubCommand (CommandObjectSP (new CommandObjectThreadUntil ()), "until", interpreter);
1220 LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-in",
1221 "Source level single step in in specified thread (current thread, if none specified).",
1222 "thread step-in [<thread-id>]",
1223 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
1224 eStepTypeInto,
1225 eStepScopeSource)),
1226 "step-in", interpreter);
1227
1228 LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-out",
1229 "Source level single step out in specified thread (current thread, if none specified).",
1230 "thread step-out [<thread-id>]",
1231 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
1232 eStepTypeOut,
1233 eStepScopeSource)),
1234 "step-out", interpreter);
1235
1236 LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-over",
1237 "Source level single step over in specified thread (current thread, if none specified).",
1238 "thread step-over [<thread-id>]",
1239 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
1240 eStepTypeOver,
1241 eStepScopeSource)),
1242 "step-over", interpreter);
1243
1244 LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst",
1245 "Single step one instruction in specified thread (current thread, if none specified).",
1246 "thread step-inst [<thread-id>]",
1247 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
1248 eStepTypeTrace,
1249 eStepScopeInstruction)),
1250 "step-inst", interpreter);
1251 LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst-over",
1252 "Single step one instruction in specified thread (current thread, if none specified), stepping over calls.",
1253 "thread step-inst-over [<thread-id>]",
1254 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
1255 eStepTypeTraceOver,
1256 eStepScopeInstruction)),
1257 "step-inst-over", interpreter);
1258}
1259
1260CommandObjectMultiwordThread::~CommandObjectMultiwordThread ()
1261{
1262}
1263
1264