1 //===-- CommandObjectThread.cpp ---------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "CommandObjectThread.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Interpreter/Options.h" 17 #include "lldb/Core/State.h" 18 #include "lldb/Core/SourceManager.h" 19 20 #include "lldb/Interpreter/CommandInterpreter.h" 21 #include "lldb/Interpreter/CommandReturnObject.h" 22 23 #include "lldb/Target/Process.h" 24 #include "lldb/Target/RegisterContext.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Target/Thread.h" 27 #include "lldb/Target/ThreadPlan.h" 28 #include "lldb/Target/ThreadPlanStepInstruction.h" 29 #include "lldb/Target/ThreadPlanStepOut.h" 30 #include "lldb/Target/ThreadPlanStepRange.h" 31 #include "lldb/Target/ThreadPlanStepInRange.h" 32 #include "lldb/Symbol/LineTable.h" 33 #include "lldb/Symbol/LineEntry.h" 34 35 using namespace lldb; 36 using namespace lldb_private; 37 38 39 bool 40 lldb_private::DisplayThreadInfo 41 ( 42 CommandInterpreter &interpreter, 43 Stream &strm, 44 Thread *thread, 45 bool only_threads_with_stop_reason, 46 bool show_source 47 ) 48 { 49 if (thread) 50 { 51 if (only_threads_with_stop_reason) 52 { 53 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 96 size_t 97 lldb_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 144 size_t 145 lldb_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 uint32_t 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 224 bool 225 lldb_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.GetDebugger().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 270 class CommandObjectThreadBacktrace : public CommandObject 271 { 272 public: 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 virtual bool 289 Execute 290 ( 291 CommandInterpreter &interpreter, 292 Args& command, 293 CommandReturnObject &result 294 ) 295 { 296 if (command.GetArgumentCount() == 0) 297 { 298 ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext()); 299 if (exe_ctx.thread) 300 { 301 bool show_frame_info = true; 302 uint32_t num_frames_with_source = 0; // Don't show any frasmes with source when backtracing 303 if (DisplayFramesForExecutionContext (exe_ctx.thread, 304 interpreter, 305 result.GetOutputStream(), 306 m_ascending, 307 0, 308 UINT32_MAX, 309 show_frame_info, 310 num_frames_with_source, 311 3, 312 3)) 313 { 314 result.SetStatus (eReturnStatusSuccessFinishResult); 315 } 316 } 317 else 318 { 319 result.AppendError ("invalid thread"); 320 result.SetStatus (eReturnStatusFailed); 321 } 322 } 323 else 324 { 325 result.AppendError ("backtrace doesn't take arguments (for now)"); 326 result.SetStatus (eReturnStatusFailed); 327 } 328 return result.Succeeded(); 329 } 330 protected: 331 bool m_ascending; 332 }; 333 334 335 enum StepScope 336 { 337 eStepScopeSource, 338 eStepScopeInstruction 339 }; 340 341 class CommandObjectThreadStepWithTypeAndScope : public CommandObject 342 { 343 public: 344 345 class CommandOptions : public Options 346 { 347 public: 348 349 CommandOptions () : 350 Options() 351 { 352 // Keep default values of all options in one place: ResetOptionValues () 353 ResetOptionValues (); 354 } 355 356 virtual 357 ~CommandOptions () 358 { 359 } 360 361 virtual Error 362 SetOptionValue (int option_idx, const char *option_arg) 363 { 364 Error error; 365 char short_option = (char) m_getopt_table[option_idx].val; 366 367 switch (short_option) 368 { 369 case 'a': 370 { 371 bool success; 372 m_avoid_no_debug = Args::StringToBoolean (option_arg, true, &success); 373 if (!success) 374 error.SetErrorStringWithFormat("Invalid boolean value for option '%c'.\n", short_option); 375 } 376 break; 377 case 'm': 378 { 379 bool found_one = false; 380 OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; 381 m_run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one); 382 if (!found_one) 383 error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option); 384 } 385 break; 386 default: 387 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); 388 break; 389 390 } 391 return error; 392 } 393 394 void 395 ResetOptionValues () 396 { 397 Options::ResetOptionValues(); 398 m_avoid_no_debug = true; 399 m_run_mode = eOnlyDuringStepping; 400 } 401 402 const lldb::OptionDefinition* 403 GetDefinitions () 404 { 405 return g_option_table; 406 } 407 408 // Options table: Required for subclasses of Options. 409 410 static lldb::OptionDefinition g_option_table[]; 411 412 // Instance variables to hold the values for command options. 413 bool m_avoid_no_debug; 414 RunMode m_run_mode; 415 }; 416 417 CommandObjectThreadStepWithTypeAndScope (const char *name, 418 const char *help, 419 const char *syntax, 420 uint32_t flags, 421 StepType step_type, 422 StepScope step_scope) : 423 CommandObject (name, help, syntax, flags), 424 m_step_type (step_type), 425 m_step_scope (step_scope), 426 m_options () 427 { 428 } 429 430 virtual 431 ~CommandObjectThreadStepWithTypeAndScope () 432 { 433 } 434 435 virtual 436 Options * 437 GetOptions () 438 { 439 return &m_options; 440 } 441 442 virtual bool 443 Execute 444 ( 445 CommandInterpreter &interpreter, 446 Args& command, 447 CommandReturnObject &result 448 ) 449 { 450 Process *process = interpreter.GetDebugger().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 m_options.m_avoid_no_debug); 517 } 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), 534 stop_other_threads, 535 false); 536 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 596 protected: 597 StepType m_step_type; 598 StepScope m_step_scope; 599 CommandOptions m_options; 600 }; 601 602 static lldb::OptionEnumValueElement 603 g_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 611 static lldb::OptionEnumValueElement 612 g_duo_running_mode[] = 613 { 614 { eOnlyThisThread, "thisThread", "Run only this thread"}, 615 { eAllThreads, "allThreads", "Run all threads"}, 616 { 0, NULL, NULL } 617 }; 618 619 lldb::OptionDefinition 620 CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] = 621 { 622 { LLDB_OPT_SET_1, false, "avoid_no_debug", 'a', required_argument, NULL, 0, "<avoid_no_debug>", "Should step-in step over functions with no debug information"}, 623 { LLDB_OPT_SET_1, false, "run_mode", 'm', required_argument, g_tri_running_mode, 0, "<run_mode>", "Determine how to run other threads while stepping this one"}, 624 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } 625 }; 626 627 628 //------------------------------------------------------------------------- 629 // CommandObjectThreadContinue 630 //------------------------------------------------------------------------- 631 632 class CommandObjectThreadContinue : public CommandObject 633 { 634 public: 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 652 ( 653 CommandInterpreter &interpreter, 654 Args& command, 655 CommandReturnObject &result 656 ) 657 { 658 bool synchronous_execution = interpreter.GetSynchronous (); 659 660 if (!interpreter.GetDebugger().GetCurrentTarget().get()) 661 { 662 result.AppendError ("invalid target, set executable file using 'file' command"); 663 result.SetStatus (eReturnStatusFailed); 664 return false; 665 } 666 667 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 668 if (process == NULL) 669 { 670 result.AppendError ("no process exists. Cannot continue"); 671 result.SetStatus (eReturnStatusFailed); 672 return false; 673 } 674 675 StateType state = process->GetState(); 676 if ((state == eStateCrashed) || (state == eStateStopped) || (state == eStateSuspended)) 677 { 678 const uint32_t num_threads = process->GetThreadList().GetSize(); 679 uint32_t idx; 680 const size_t argc = command.GetArgumentCount(); 681 if (argc > 0) 682 { 683 std::vector<uint32_t> resume_thread_indexes; 684 for (uint32_t i=0; i<argc; ++i) 685 { 686 idx = Args::StringToUInt32 (command.GetArgumentAtIndex(0), LLDB_INVALID_INDEX32); 687 if (idx < num_threads) 688 resume_thread_indexes.push_back(idx); 689 else 690 result.AppendWarningWithFormat("Thread index %u out of range.\n", idx); 691 } 692 693 if (resume_thread_indexes.empty()) 694 { 695 result.AppendError ("no valid thread indexes were specified"); 696 result.SetStatus (eReturnStatusFailed); 697 return false; 698 } 699 else 700 { 701 result.AppendMessage ("Resuming thread "); 702 for (idx=0; idx<num_threads; ++idx) 703 { 704 Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get(); 705 if (find(resume_thread_indexes.begin(), resume_thread_indexes.end(), idx) != resume_thread_indexes.end()) 706 { 707 result.AppendMessageWithFormat ("%u ", idx); 708 thread->SetResumeState (eStateRunning); 709 } 710 else 711 { 712 thread->SetResumeState (eStateSuspended); 713 } 714 } 715 result.AppendMessageWithFormat ("in process %i\n", process->GetID()); 716 } 717 } 718 else 719 { 720 Thread *current_thread = process->GetThreadList().GetCurrentThread().get(); 721 if (current_thread == NULL) 722 { 723 result.AppendError ("the process doesn't have a current thread"); 724 result.SetStatus (eReturnStatusFailed); 725 return false; 726 } 727 // Set the actions that the threads should each take when resuming 728 for (idx=0; idx<num_threads; ++idx) 729 { 730 Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get(); 731 if (thread == current_thread) 732 { 733 result.AppendMessageWithFormat ("Resuming thread 0x%4.4x in process %i\n", thread->GetID(), process->GetID()); 734 thread->SetResumeState (eStateRunning); 735 } 736 else 737 { 738 thread->SetResumeState (eStateSuspended); 739 } 740 } 741 } 742 743 Error error (process->Resume()); 744 if (error.Success()) 745 { 746 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID()); 747 if (synchronous_execution) 748 { 749 StateType state = process->WaitForProcessToStop (NULL); 750 751 result.SetDidChangeProcessState (true); 752 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); 753 result.SetStatus (eReturnStatusSuccessFinishNoResult); 754 } 755 else 756 { 757 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 758 } 759 } 760 else 761 { 762 result.AppendErrorWithFormat("Failed to resume process: %s\n", error.AsCString()); 763 result.SetStatus (eReturnStatusFailed); 764 } 765 } 766 else 767 { 768 result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n", 769 StateAsCString(state)); 770 result.SetStatus (eReturnStatusFailed); 771 } 772 773 return result.Succeeded(); 774 } 775 776 }; 777 778 //------------------------------------------------------------------------- 779 // CommandObjectThreadUntil 780 //------------------------------------------------------------------------- 781 782 class CommandObjectThreadUntil : public CommandObject 783 { 784 public: 785 786 class CommandOptions : public Options 787 { 788 public: 789 uint32_t m_thread_idx; 790 uint32_t m_frame_idx; 791 792 CommandOptions () : 793 Options(), 794 m_thread_idx(LLDB_INVALID_THREAD_ID), 795 m_frame_idx(LLDB_INVALID_FRAME_ID) 796 { 797 // Keep default values of all options in one place: ResetOptionValues () 798 ResetOptionValues (); 799 } 800 801 virtual 802 ~CommandOptions () 803 { 804 } 805 806 virtual Error 807 SetOptionValue (int option_idx, const char *option_arg) 808 { 809 Error error; 810 char short_option = (char) m_getopt_table[option_idx].val; 811 812 switch (short_option) 813 { 814 case 't': 815 { 816 uint32_t m_thread_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_INDEX32); 817 if (m_thread_idx == LLDB_INVALID_INDEX32) 818 { 819 error.SetErrorStringWithFormat ("Invalid thread index '%s'.\n", option_arg); 820 } 821 } 822 break; 823 case 'f': 824 { 825 m_frame_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_FRAME_ID); 826 if (m_frame_idx == LLDB_INVALID_FRAME_ID) 827 { 828 error.SetErrorStringWithFormat ("Invalid frame index '%s'.\n", option_arg); 829 } 830 } 831 break; 832 case 'm': 833 { 834 bool found_one = false; 835 OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; 836 lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one); 837 838 if (!found_one) 839 error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option); 840 else if (run_mode == eAllThreads) 841 m_stop_others = false; 842 else 843 m_stop_others = true; 844 845 } 846 break; 847 default: 848 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); 849 break; 850 851 } 852 return error; 853 } 854 855 void 856 ResetOptionValues () 857 { 858 Options::ResetOptionValues(); 859 m_thread_idx = LLDB_INVALID_THREAD_ID; 860 m_frame_idx = 0; 861 m_stop_others = false; 862 } 863 864 const lldb::OptionDefinition* 865 GetDefinitions () 866 { 867 return g_option_table; 868 } 869 870 uint32_t m_step_thread_idx; 871 bool m_stop_others; 872 873 // Options table: Required for subclasses of Options. 874 875 static lldb::OptionDefinition g_option_table[]; 876 877 // Instance variables to hold the values for command options. 878 }; 879 880 CommandObjectThreadUntil () : 881 CommandObject ("thread until", 882 "Runs the current or specified thread until it reaches a given line number or leaves the current function.", 883 "thread until [<cmd-options>] <line-number>", 884 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused), 885 m_options () 886 { 887 } 888 889 890 virtual 891 ~CommandObjectThreadUntil () 892 { 893 } 894 895 virtual 896 Options * 897 GetOptions () 898 { 899 return &m_options; 900 } 901 902 virtual bool 903 Execute 904 ( 905 CommandInterpreter &interpreter, 906 Args& command, 907 CommandReturnObject &result 908 ) 909 { 910 bool synchronous_execution = interpreter.GetSynchronous (); 911 912 if (!interpreter.GetDebugger().GetCurrentTarget().get()) 913 { 914 result.AppendError ("invalid target, set executable file using 'file' command"); 915 result.SetStatus (eReturnStatusFailed); 916 return false; 917 } 918 919 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 920 if (process == NULL) 921 { 922 result.AppendError ("need a valid process to step"); 923 result.SetStatus (eReturnStatusFailed); 924 925 } 926 else 927 { 928 Thread *thread = NULL; 929 uint32_t line_number; 930 931 if (command.GetArgumentCount() != 1) 932 { 933 result.AppendErrorWithFormat ("No line number provided:\n%s", GetSyntax()); 934 result.SetStatus (eReturnStatusFailed); 935 return false; 936 } 937 938 line_number = Args::StringToUInt32 (command.GetArgumentAtIndex(0), UINT32_MAX); 939 if (line_number == UINT32_MAX) 940 { 941 result.AppendErrorWithFormat ("Invalid line number: '%s'.\n", command.GetArgumentAtIndex(0)); 942 result.SetStatus (eReturnStatusFailed); 943 return false; 944 } 945 946 if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) 947 { 948 thread = process->GetThreadList().GetCurrentThread().get(); 949 } 950 else 951 { 952 thread = process->GetThreadList().GetThreadAtIndex(m_options.m_thread_idx).get(); 953 } 954 955 if (thread == NULL) 956 { 957 const uint32_t num_threads = process->GetThreadList().GetSize(); 958 result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n", m_options.m_thread_idx, 0, num_threads); 959 result.SetStatus (eReturnStatusFailed); 960 return false; 961 } 962 963 const bool abort_other_plans = true; 964 965 StackFrame *frame = thread->GetStackFrameAtIndex(m_options.m_frame_idx).get(); 966 if (frame == NULL) 967 { 968 969 result.AppendErrorWithFormat ("Frame index %u is out of range for thread %u.\n", m_options.m_frame_idx, m_options.m_thread_idx); 970 result.SetStatus (eReturnStatusFailed); 971 return false; 972 } 973 974 ThreadPlan *new_plan; 975 976 if (frame->HasDebugInformation ()) 977 { 978 // Finally we got here... Translate the given line number to a bunch of addresses: 979 SymbolContext sc(frame->GetSymbolContext (eSymbolContextCompUnit)); 980 LineTable *line_table = NULL; 981 if (sc.comp_unit) 982 line_table = sc.comp_unit->GetLineTable(); 983 984 if (line_table == NULL) 985 { 986 result.AppendErrorWithFormat ("Failed to resolve the line table for frame %u of thread index %u.\n", 987 m_options.m_frame_idx, m_options.m_thread_idx); 988 result.SetStatus (eReturnStatusFailed); 989 return false; 990 } 991 992 LineEntry function_start; 993 uint32_t index_ptr = 0, end_ptr; 994 std::vector<addr_t> address_list; 995 996 // Find the beginning & end index of the 997 AddressRange fun_addr_range = sc.function->GetAddressRange(); 998 Address fun_start_addr = fun_addr_range.GetBaseAddress(); 999 line_table->FindLineEntryByAddress (fun_start_addr, function_start, &index_ptr); 1000 1001 Address fun_end_addr(fun_start_addr.GetSection(), fun_start_addr.GetOffset() + fun_addr_range.GetByteSize()); 1002 line_table->FindLineEntryByAddress (fun_end_addr, function_start, &end_ptr); 1003 1004 while (index_ptr <= end_ptr) 1005 { 1006 LineEntry line_entry; 1007 index_ptr = sc.comp_unit->FindLineEntry(index_ptr, line_number, sc.comp_unit, &line_entry); 1008 if (index_ptr == UINT32_MAX) 1009 break; 1010 1011 addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(process); 1012 if (address != LLDB_INVALID_ADDRESS) 1013 address_list.push_back (address); 1014 index_ptr++; 1015 } 1016 1017 new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, address_list.data(), address_list.size(), m_options.m_stop_others); 1018 new_plan->SetOkayToDiscard(false); 1019 } 1020 else 1021 { 1022 result.AppendErrorWithFormat ("Frame index %u of thread %u has no debug information.\n", m_options.m_frame_idx, m_options.m_thread_idx); 1023 result.SetStatus (eReturnStatusFailed); 1024 return false; 1025 1026 } 1027 1028 process->GetThreadList().SetCurrentThreadByID (m_options.m_thread_idx); 1029 Error error (process->Resume ()); 1030 if (error.Success()) 1031 { 1032 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID()); 1033 if (synchronous_execution) 1034 { 1035 StateType state = process->WaitForProcessToStop (NULL); 1036 1037 result.SetDidChangeProcessState (true); 1038 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); 1039 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1040 } 1041 else 1042 { 1043 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 1044 } 1045 } 1046 else 1047 { 1048 result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString()); 1049 result.SetStatus (eReturnStatusFailed); 1050 } 1051 1052 } 1053 return result.Succeeded(); 1054 } 1055 protected: 1056 CommandOptions m_options; 1057 1058 }; 1059 1060 lldb::OptionDefinition 1061 CommandObjectThreadUntil::CommandOptions::g_option_table[] = 1062 { 1063 { LLDB_OPT_SET_1, false, "frame", 'f', required_argument, NULL, 0, "<frame>", "Frame index for until operation - defaults to 0"}, 1064 { LLDB_OPT_SET_1, false, "thread", 't', required_argument, NULL, 0, "<thread>", "Thread index for the thread for until operation"}, 1065 { LLDB_OPT_SET_1, false, "run_mode",'m', required_argument, g_duo_running_mode, 0, "<run_mode>","Determine how to run other threads while stepping this one"}, 1066 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } 1067 }; 1068 1069 1070 //------------------------------------------------------------------------- 1071 // CommandObjectThreadSelect 1072 //------------------------------------------------------------------------- 1073 1074 class CommandObjectThreadSelect : public CommandObject 1075 { 1076 public: 1077 1078 CommandObjectThreadSelect () : 1079 CommandObject ("thread select", 1080 "Selects a threads as the currently active thread.", 1081 "thread select <thread-index>", 1082 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) 1083 { 1084 } 1085 1086 1087 virtual 1088 ~CommandObjectThreadSelect () 1089 { 1090 } 1091 1092 virtual bool 1093 Execute 1094 ( 1095 CommandInterpreter &interpreter, 1096 Args& command, 1097 CommandReturnObject &result 1098 ) 1099 { 1100 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 1101 if (process == NULL) 1102 { 1103 result.AppendError ("no process"); 1104 result.SetStatus (eReturnStatusFailed); 1105 return false; 1106 } 1107 else if (command.GetArgumentCount() != 1) 1108 { 1109 result.AppendErrorWithFormat("'%s' takes exactly one thread index argument:\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); 1110 result.SetStatus (eReturnStatusFailed); 1111 return false; 1112 } 1113 1114 uint32_t index_id = Args::StringToUInt32(command.GetArgumentAtIndex(0), 0, 0); 1115 1116 Thread *new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get(); 1117 if (new_thread == NULL) 1118 { 1119 result.AppendErrorWithFormat ("Invalid thread #%s.\n", command.GetArgumentAtIndex(0)); 1120 result.SetStatus (eReturnStatusFailed); 1121 return false; 1122 } 1123 1124 process->GetThreadList().SetCurrentThreadByID(new_thread->GetID()); 1125 1126 DisplayThreadInfo (interpreter, 1127 result.GetOutputStream(), 1128 new_thread, 1129 false, 1130 true); 1131 1132 return result.Succeeded(); 1133 } 1134 1135 }; 1136 1137 1138 //------------------------------------------------------------------------- 1139 // CommandObjectThreadList 1140 //------------------------------------------------------------------------- 1141 1142 class CommandObjectThreadList : public CommandObject 1143 { 1144 public: 1145 1146 1147 CommandObjectThreadList (): 1148 CommandObject ("thread list", 1149 "Shows a summary of all current threads in a process.", 1150 "thread list", 1151 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) 1152 { 1153 } 1154 1155 ~CommandObjectThreadList() 1156 { 1157 } 1158 1159 bool 1160 Execute 1161 ( 1162 CommandInterpreter &interpreter, 1163 Args& command, 1164 CommandReturnObject &result 1165 ) 1166 { 1167 StreamString &strm = result.GetOutputStream(); 1168 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1169 ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext()); 1170 if (exe_ctx.process) 1171 { 1172 const StateType state = exe_ctx.process->GetState(); 1173 1174 if (StateIsStoppedState(state)) 1175 { 1176 if (state == eStateExited) 1177 { 1178 int exit_status = exe_ctx.process->GetExitStatus(); 1179 const char *exit_description = exe_ctx.process->GetExitDescription(); 1180 strm.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n", 1181 exe_ctx.process->GetID(), 1182 exit_status, 1183 exit_status, 1184 exit_description ? exit_description : ""); 1185 } 1186 else 1187 { 1188 strm.Printf ("Process %d state is %s\n", exe_ctx.process->GetID(), StateAsCString (state)); 1189 if (exe_ctx.thread == NULL) 1190 exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get(); 1191 if (exe_ctx.thread != NULL) 1192 { 1193 DisplayThreadsInfo (interpreter, &exe_ctx, result, false, false); 1194 } 1195 else 1196 { 1197 result.AppendError ("no valid thread found in current process"); 1198 result.SetStatus (eReturnStatusFailed); 1199 } 1200 } 1201 } 1202 else 1203 { 1204 result.AppendError ("process is currently running"); 1205 result.SetStatus (eReturnStatusFailed); 1206 } 1207 } 1208 else 1209 { 1210 result.AppendError ("no current location or status available"); 1211 result.SetStatus (eReturnStatusFailed); 1212 } 1213 return result.Succeeded(); 1214 } 1215 }; 1216 1217 //------------------------------------------------------------------------- 1218 // CommandObjectMultiwordThread 1219 //------------------------------------------------------------------------- 1220 1221 CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter &interpreter) : 1222 CommandObjectMultiword ("thread", 1223 "A set of commands for operating on one or more thread within a running process.", 1224 "thread <subcommand> [<subcommand-options>]") 1225 { 1226 LoadSubCommand (interpreter, "backtrace", CommandObjectSP (new CommandObjectThreadBacktrace ())); 1227 LoadSubCommand (interpreter, "continue", CommandObjectSP (new CommandObjectThreadContinue ())); 1228 LoadSubCommand (interpreter, "list", CommandObjectSP (new CommandObjectThreadList ())); 1229 LoadSubCommand (interpreter, "select", CommandObjectSP (new CommandObjectThreadSelect ())); 1230 LoadSubCommand (interpreter, "until", CommandObjectSP (new CommandObjectThreadUntil ())); 1231 LoadSubCommand (interpreter, "step-in", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ( 1232 "thread step-in", 1233 "Source level single step in in specified thread (current thread, if none specified).", 1234 "thread step-in [<thread-id>]", 1235 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, 1236 eStepTypeInto, 1237 eStepScopeSource))); 1238 1239 LoadSubCommand (interpreter, "step-out", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-out", 1240 "Source level single step out in specified thread (current thread, if none specified).", 1241 "thread step-out [<thread-id>]", 1242 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, 1243 eStepTypeOut, 1244 eStepScopeSource))); 1245 1246 LoadSubCommand (interpreter, "step-over", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-over", 1247 "Source level single step over in specified thread (current thread, if none specified).", 1248 "thread step-over [<thread-id>]", 1249 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, 1250 eStepTypeOver, 1251 eStepScopeSource))); 1252 1253 LoadSubCommand (interpreter, "step-inst", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst", 1254 "Single step one instruction in specified thread (current thread, if none specified).", 1255 "thread step-inst [<thread-id>]", 1256 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, 1257 eStepTypeTrace, 1258 eStepScopeInstruction))); 1259 1260 LoadSubCommand (interpreter, "step-inst-over", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst-over", 1261 "Single step one instruction in specified thread (current thread, if none specified), stepping over calls.", 1262 "thread step-inst-over [<thread-id>]", 1263 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, 1264 eStepTypeTraceOver, 1265 eStepScopeInstruction))); 1266 } 1267 1268 CommandObjectMultiwordThread::~CommandObjectMultiwordThread () 1269 { 1270 } 1271 1272 1273