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